diff options
183 files changed, 5116 insertions, 4962 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 9883f87c16..26bd27754f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -197,12 +197,11 @@ task: task: name: 'macOS 11 native [gui] [no depends]' brew_install_script: - - brew update - brew install boost libevent berkeley-db4 qt@5 miniupnpc libnatpmp ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt << : *GLOBAL_TASK_TEMPLATE osx_instance: # Use latest image, but hardcode version to avoid silent upgrades (and breaks) - image: big-sur-xcode-12.4 # https://cirrus-ci.org/guide/macOS + image: big-sur-xcode-12.5 # https://cirrus-ci.org/guide/macOS env: << : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV CI_USE_APT_INSTALL: "no" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ae2379fbd5..5cd4715ef0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,8 +57,8 @@ Communication Channels ---------------------- Most communication about Bitcoin Core development happens on IRC, in the -`#bitcoin-core-dev` channel on Freenode. The easiest way to participate on IRC is -with the web client, [webchat.freenode.net](https://webchat.freenode.net/). Chat +`#bitcoin-core-dev` channel on Libera Chat. The easiest way to participate on IRC is +with the web client, [web.libera.chat](https://web.libera.chat/#bitcoin-core-dev). Chat history logs can be found on [http://www.erisian.com.au/bitcoin-core-dev/](http://www.erisian.com.au/bitcoin-core-dev/) and [http://gnusha.org/bitcoin-core-dev/](http://gnusha.org/bitcoin-core-dev/). diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index 2ae33f7140..7aac53c815 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -11,7 +11,7 @@ # Test for the Boost C++ libraries of a particular version (or newer) # # If no path to the installed boost library is given the macro searchs -# under /usr, /usr/local, /opt and /opt/local and evaluates the +# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates the # $BOOST_ROOT environment variable. Further documentation is available at # <http://randspringer.de/boost/index.html>. # @@ -151,7 +151,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ else search_libsubdirs="$multiarch_libsubdir $libsubdirs" fi - for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew/; do if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then for libsubdir in $search_libsubdirs ; do if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi @@ -227,7 +227,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ fi else if test "x$cross_compiling" != "xyes" ; then - for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local /opt/homebrew ; do if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 0995ef1406..232a79bb36 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -146,6 +146,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ dnl https://bugreports.qt.io/browse/QTBUG-27097. AX_CHECK_LINK_FLAG([-lwtsapi32], [QT_LIBS="$QT_LIBS -lwtsapi32"], [AC_MSG_ERROR([could not link against -lwtsapi32])]) _BITCOIN_QT_CHECK_STATIC_PLUGIN([QWindowsIntegrationPlugin], [-lqwindows]) + _BITCOIN_QT_CHECK_STATIC_PLUGIN([QWindowsVistaStylePlugin], [-lqwindowsvistastyle]) AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) elif test "x$TARGET_OS" = xlinux; then dnl workaround for https://bugreports.qt.io/browse/QTBUG-74874 diff --git a/build_msvc/common.qt.init.vcxproj b/build_msvc/common.qt.init.vcxproj index 837c088451..68ad06c4ac 100644 --- a/build_msvc/common.qt.init.vcxproj +++ b/build_msvc/common.qt.init.vcxproj @@ -9,8 +9,8 @@ <QtIncludes>$(QtIncludeDir);$(QtIncludeDir)\QtNetwork;$(QtIncludeDir)\QtCore;$(QtIncludeDir)\QtWidgets;$(QtIncludeDir)\QtGui;</QtIncludes> <GeneratedFilesOutDir>.\QtGeneratedFiles\qt</GeneratedFilesOutDir> <QtToolsDir>$(QtBaseDir)\bin</QtToolsDir> - <QtReleaseLibraries>$(QtPluginsLibraryDir)\platforms\qminimal.lib;$(QtPluginsLibraryDir)\platforms\qwindows.lib;$(QtLibraryDir)\Qt5WindowsUIAutomationSupport.lib;$(QtLibraryDir)\qtfreetype.lib;$(QtLibraryDir)\qtharfbuzz.lib;$(QtLibraryDir)\qtlibpng.lib;$(QtLibraryDir)\qtpcre2.lib;$(QtLibraryDir)\Qt5AccessibilitySupport.lib;$(QtLibraryDir)\Qt5Core.lib;$(QtLibraryDir)\Qt5Concurrent.lib;$(QtLibraryDir)\Qt5EventDispatcherSupport.lib;$(QtLibraryDir)\Qt5FontDatabaseSupport.lib;$(QtLibraryDir)\Qt5Gui.lib;$(QtLibraryDir)\Qt5Network.lib;$(QtLibraryDir)\Qt5PlatformCompositorSupport.lib;$(QtLibraryDir)\Qt5ThemeSupport.lib;$(QtLibraryDir)\Qt5Widgets.lib;$(QtLibraryDir)\Qt5WinExtras.lib;$(QtLibraryDir)\qtmain.lib;Wtsapi32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtReleaseLibraries> - <QtDebugLibraries>$(QtPluginsLibraryDir)\platforms\qwindowsd.lib;$(QtPluginsLibraryDir)\platforms\qminimald.lib;$(QtLibraryDir)\*d.lib;Wtsapi32.lib;crypt32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtDebugLibraries> + <QtReleaseLibraries>$(QtPluginsLibraryDir)\platforms\qminimal.lib;$(QtPluginsLibraryDir)\platforms\qwindows.lib;$(QtPluginsLibraryDir)\styles\qwindowsvistastyle.lib;$(QtLibraryDir)\Qt5WindowsUIAutomationSupport.lib;$(QtLibraryDir)\qtfreetype.lib;$(QtLibraryDir)\qtharfbuzz.lib;$(QtLibraryDir)\qtlibpng.lib;$(QtLibraryDir)\qtpcre2.lib;$(QtLibraryDir)\Qt5AccessibilitySupport.lib;$(QtLibraryDir)\Qt5Core.lib;$(QtLibraryDir)\Qt5Concurrent.lib;$(QtLibraryDir)\Qt5EventDispatcherSupport.lib;$(QtLibraryDir)\Qt5FontDatabaseSupport.lib;$(QtLibraryDir)\Qt5Gui.lib;$(QtLibraryDir)\Qt5Network.lib;$(QtLibraryDir)\Qt5PlatformCompositorSupport.lib;$(QtLibraryDir)\Qt5ThemeSupport.lib;$(QtLibraryDir)\Qt5Widgets.lib;$(QtLibraryDir)\Qt5WinExtras.lib;$(QtLibraryDir)\qtmain.lib;Wtsapi32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtReleaseLibraries> + <QtDebugLibraries>$(QtPluginsLibraryDir)\platforms\qwindowsd.lib;$(QtPluginsLibraryDir)\platforms\qminimald.lib;$(QtPluginsLibraryDir)\styles\qwindowsvistastyled.lib;$(QtLibraryDir)\*d.lib;Wtsapi32.lib;crypt32.lib;userenv.lib;netapi32.lib;imm32.lib;Dwmapi.lib;version.lib;winmm.lib;UxTheme.lib</QtDebugLibraries> </PropertyGroup> </Project> diff --git a/contrib/debian/copyright b/contrib/debian/copyright index bc5535b4c7..6d23f600c3 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -1,7 +1,7 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Bitcoin Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com> - irc://#bitcoin@freenode.net + irc://#bitcoin-core-dev@libera.chat Source: https://github.com/bitcoin/bitcoin Files: * diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 103e249e33..bed3531720 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -56,7 +56,6 @@ script: | HOST_CXXFLAGS="-O2 -g" HOST_LDFLAGS_BASE="-static-libstdc++ -Wl,-O2" - export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TZ="UTC" export BUILD_DIR="$PWD" mkdir -p ${WRAP_DIR} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index d6c41b2c43..1d4506e3c2 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -42,7 +42,6 @@ script: | FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date dmg xorrisofs" - export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TZ="UTC" export BUILD_DIR="$PWD" mkdir -p ${WRAP_DIR} diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index eabcdaa79d..03eba71366 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -38,7 +38,6 @@ script: | HOST_CFLAGS="-O2 -g -fno-ident" HOST_CXXFLAGS="-O2 -g -fno-ident" - export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TZ="UTC" export BUILD_DIR="$PWD" mkdir -p ${WRAP_DIR} diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 00cb494963..46bfa29b74 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -178,7 +178,6 @@ case "$HOST" in esac # Environment variables for determinism -export QT_RCC_SOURCE_DATE_OVERRIDE=1 export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name" export TZ="UTC" case "$HOST" in diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 9560b586ec..dbecba7d1d 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -37,7 +37,7 @@ import re class BIP155Network(Enum): IPV4 = 1 IPV6 = 2 - TORV2 = 3 + TORV2 = 3 # no longer supported TORV3 = 4 I2P = 5 CJDNS = 6 @@ -46,11 +46,11 @@ def name_to_bip155(addr): '''Convert address string to BIP155 (networkID, addr) tuple.''' if addr.endswith('.onion'): vchAddr = b32decode(addr[0:-6], True) - if len(vchAddr) == 10: - return (BIP155Network.TORV2, vchAddr) - elif len(vchAddr) == 35: - assert(vchAddr[34] == 3) + if len(vchAddr) == 35: + assert vchAddr[34] == 3 return (BIP155Network.TORV3, vchAddr[:32]) + elif len(vchAddr) == 10: + return (BIP155Network.TORV2, vchAddr) else: raise ValueError('Invalid onion %s' % vchAddr) elif addr.endswith('.b32.i2p'): @@ -100,7 +100,10 @@ def parse_spec(s): host = name_to_bip155(host) - return host + (port, ) + if host[0] == BIP155Network.TORV2: + return None # TORV2 is no longer supported, so we ignore it + else: + return host + (port, ) def ser_compact_size(l): r = b"" @@ -136,6 +139,8 @@ def process_nodes(g, f, structname): continue spec = parse_spec(line) + if spec is None: # ignore this entry (e.g. no longer supported addresses like TORV2) + continue blob = bip155_serialize(spec) hoststr = ','.join(('0x%02x' % b) for b in blob) g.write(f' {hoststr},\n') diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index 7300e3043d..a62150a930 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -650,518 +650,6 @@ [2a0f:df00:0:254::46]:8333 [2c0f:f598:5:1:1001::1]:8333 [2c0f:fce8:0:400:b7c::1]:8333 -226eupdnaouu4h2v.onion:8333 -22h7b6f3caabqqsu.onion:8333 -23wdfqkzttmenvki.onion:8333 -23yi3frxymtwdgre.onion:8333 -2ajon3moyf4i2hbb.onion:8333 -2bfmlpk55hffpl6e.onion:8333 -2ckmbf6sglwydeth.onion:8333 -2hkusi5gcaautwqf.onion:8333 -2ivhmlbxbgnkcykl.onion:8333 -2mmxouhv6nebowkq.onion:8333 -2qsnv6exnuuiar7z.onion:8333 -2qudbhlnvqpli3sz.onion:8333 -2ujxdfovfyjpmdto.onion:8333 -2xdgeufrek3eumkw.onion:8333 -2xdzsruhsej4tsiw.onion:8333 -34ran2woq4easmss.onion:8333 -36q7khhej2lxd3wf.onion:8333 -373wjdspuo52utzq.onion:8333 -376klet5xqbrg2jv.onion:8333 -37kwd7fxop766l5k.onion:8333 -3e5t7hq4alt5tovx.onion:8333 -3gbxhebfhouuwgc3.onion:8333 -3hgbjze2nbwyuewf.onion:8333 -3iuuvrd2waha2cxo.onion:8333 -3jtxujdaiwh6iltu.onion:8333 -3l5eq2du7mvscj4a.onion:8333 -3nofngnqlqeehn7o.onion:8333 -3r44ddzjitznyahw.onion:8333 -3vtbuwmton7vq5qz.onion:8333 -46ohzttz4peki43g.onion:8333 -47fl3ivl4v56jstr.onion:8333 -47i6qrl2ijqcwlg6.onion:8333 -47uupgzcnrwahoto.onion:8333 -4c5cki37evofds6d.onion:8333 -4eq36jrx7xuytfpc.onion:8333 -4ewkdxvcg57adrni.onion:8333 -4flvgibnm2nld3na.onion:8333 -4iaontym47imawe4.onion:8333 -4jxz37oou5ag763c.onion:8333 -4mnkvj6ha73eqnbk.onion:8333 -4nnuyxm5k5tlyjq3.onion:8333 -4nz2yg4cnote3ej7.onion:8333 -4pozwh6564ygzddk.onion:8333 -4qgfb56rvpbmesx7.onion:8333 -4rsax23taqzwmimj.onion:8333 -4u5j5ay6rasowt4m.onion:8333 -4vorvtoyegh4zbvr.onion:8333 -52s4j5pldwlpzhtw.onion:8333 -5abpiiqfvekoejro.onion:8333 -5aydzxx6jyoz3nez.onion:8333 -5cxzdsrtok5dgo4a.onion:8333 -5eduikpudie3jyrf.onion:8333 -5epeafkmya4fv5d5.onion:8333 -5fyxlztic3t6notz.onion:8333 -5hd6eyew5ybnq6gb.onion:8333 -5jyfzhwksb6urrp2.onion:8333 -5nooqgct567ig57v.onion:8333 -5nsfm4nqqzzprjrp.onion:8333 -5oqstxspzhlgjef6.onion:8333 -5pzzmd4tfonrqzb2.onion:8333 -5sckmx4yucbnp4io.onion:8333 -5ue7worzbn6hon3e.onion:8333 -5wxhx2tozpovf6z3.onion:8333 -5xk3yun36e32e34i.onion:8333 -5zght2g7vcsapi65.onion:8333 -62dcdpvdolfzkdzl.onion:8333 -63bko2mhixnn2b7d.onion:8333 -67hjvfv6wictalm5.onion:8333 -6g6ko4klkf5atldi.onion:8333 -6k5zreexw4cadxi5.onion:8333 -6kf5ayhlpenywgas.onion:8333 -6maigxjvcet4pite.onion:8333 -6ressv4dvplb5ihh.onion:8333 -6rjex6gyuaui3c5e.onion:8333 -6skgnf43pphdvjua.onion:8333 -6stxaoduwisg5sqh.onion:8333 -6xqy4ts6bo6u5dgm.onion:8333 -7avnl3dqpgu23jva.onion:8333 -7ff4wk266no23txn.onion:8333 -7hipbuzfdcyzqkkg.onion:8333 -7sjmlzrthjlpfydk.onion:8333 -7tut3zt2akwrmw6x.onion:8333 -7uhsjzj6nx3dfnxt.onion:8333 -7wm4wso3wvatxnbt.onion:8333 -7ykmzuybwd2ptzg4.onion:8333 -a27bvhina4y23jxo.onion:8333 -a53vtdm7uiet5vdl.onion:8333 -a56572xjuofnt2dp.onion:8333 -abp25knifdsnc2rv.onion:8333 -aefx7ubzpal7clak.onion:8333 -ai5r2diozoe7rrdz.onion:8333 -aipupphit3enggpj.onion:8333 -algpjjygd3gtnmpp.onion:8333 -alihua7rhyc452hr.onion:8333 -am3gyyfynxzwyxhx.onion:8333 -ankozzfhl2r3uc6u.onion:8333 -at3twjlbtc2lqnq5.onion:8333 -avqobl72pmc64dyi.onion:8333 -awmdz2fs3b5h5ut5.onion:8333 -ayywpiy77butdjrj.onion:8333 -b2i3pj7c24cvprs7.onion:8333 -b4ilebyxcu6nttio.onion:8333 -b4vvkbqipcmkwp4v.onion:8333 -bddfqxps5ibd3ftw.onion:8333 -be5bgcpo4ooux5qy.onion:8333 -bgla4m6zetvtv7ls.onion:8333 -bh32gzw3nyckzqut.onion:8333 -bho4kodpehn7xr3x.onion:8333 -bitcoin4rlfa4wqx.onion:8333 -biw7s6jf6r2mf3cu.onion:8333 -bk7yp6epnmcllq72.onion:8333 -blcktrgve5vetjsk.onion:8333 -blwbp7gfdffdsx4g.onion:8333 -bnxn6qqc55gvn5op.onion:8333 -bp7o22lvcjawelvv.onion:8333 -bqqyqucgj4tchn64.onion:8333 -bvdzmutcqf7gzzn5.onion:8333 -c36zmegjkinftmtf.onion:8333 -c4fn62gnltlgrptv.onion:8333 -caael5yedviooqzk.onion:8333 -caq54ablfbrnumdd.onion:8333 -cernrmrk5zomzozn.onion:8333 -chri6itgjaagof4t.onion:8333 -cncwik3tnd2ejm5z.onion:8333 -cuyjqoziemcmwaxl.onion:8333 -cx7qa2gpqyp7pld5.onion:8333 -czp7wgaus4gvio72.onion:8333 -d2fn54rfyjdangi4.onion:8333 -d2sk45u6ca64yeqh.onion:8333 -d3aowmngvktsziae.onion:8333 -d5iu4aiz3y2kgcgj.onion:8333 -d6zbw2sxnxgj5sv3.onion:8333 -db5rd5e46t7mgini.onion:8333 -dci2gulorl44yj55.onion:8333 -ddpth2mwt3rsvoog.onion:8333 -dfrwza7fcecknnms.onion:8333 -djwhjfj4rh3oz3yj.onion:8333 -dkk5mmpe5jtjodk5.onion:8333 -doj3zgmsbzurmqgp.onion:8333 -dpce4f3rcqddzbx5.onion:8333 -drwo3vnxch5ozfbo.onion:8333 -duikkidxip3lyexn.onion:8333 -duqdliptc22i6hf5.onion:8333 -duyp4coh5d7nh3ud.onion:8333 -duz5two3z7c55lxj.onion:8333 -dvu6dlar6ezc6xen.onion:8333 -dy6zqs46ycleayyp.onion:8333 -dz2ydmj3yqrcm4r7.onion:8333 -e2b2a5suvdawzxud.onion:8333 -e33h57j2ewkkqsn5.onion:8333 -e5kjiay7pzj5qpzv.onion:8333 -e7iko42d2wzcmvy4.onion:8333 -ea6boh4kotq56ws5.onion:8333 -efdx6gc4s5ezyqeg.onion:8333 -efrpuuic6ukeyqcs.onion:8333 -egruc3bi3itru6gq.onion:8333 -erc6tjs2ucyadl23.onion:8333 -eue2n5sk5tktg5bv.onion:8333 -ezkr7stq4w7ohjrt.onion:8333 -f3nyyjba6kpxznhk.onion:8333 -faq73vj4pcs73thu.onion:8333 -fdvtlj3pscbxuh75.onion:8333 -fgdpxov4nzxvhcpv.onion:8333 -fisqq6vzk3m6t225.onion:8333 -fkgp3qwegacrd2bj.onion:8333 -fo3tdfwx27takqq5.onion:8333 -fqkxtchwypispkpv.onion:8333 -fqunuhlwvd7rq6d5.onion:8333 -frwt5mscpyhiuwpe.onion:8333 -fta4gfjiuv6f2le2.onion:8333 -fuoy2ipuqrqwe5cf.onion:8333 -fz6nsij6jiyuwlsc.onion:8333 -g3vlnaaaog5sgui5.onion:8333 -g44i6jwsutkwmspz.onion:8333 -g55t65d5ckjixcnw.onion:8333 -gajd6eyrl2qwkfmg.onion:8333 -gblue3hr53p4grx7.onion:8333 -gbpro5tzduiuff4v.onion:8333 -gc4l3tql32qhfgmi.onion:8333 -gcnlorvtpycuajc6.onion:8333 -gdsib2nk2eeoidgc.onion:8333 -ge5gm7c6w7yahpz7.onion:8333 -gegcteeep4cwftl5.onion:8333 -gfoyraudgv5qjdku.onion:8333 -ggpbuypmxgi26lc6.onion:8333 -ghqivye7cfckisnt.onion:8333 -girakxomne5fby64.onion:8333 -glz5gfk33tuug5ne.onion:8333 -gplatxoyg5nxl5rj.onion:8333 -gripl5xjwy2dcr6c.onion:8333 -gthhzlmqci22nxru.onion:8333 -gto2d64swosfmk6c.onion:8333 -guaciney52mgcbp2.onion:8333 -gwktgrmtwk6nv5sc.onion:8333 -gwoxnokdcwc7hy4p.onion:8333 -h333f4qnwe7mrymn.onion:8333 -h6a32n4blbwwyn4d.onion:8333 -hafwtrbooszoembm.onion:8333 -hbwhgsb3eeinnr6t.onion:8333 -hcv6foxh5mk7fhb5.onion:8333 -hd6hktcl6wamzlzm.onion:8333 -hda6msa4v4rt77gx.onion:8333 -hdgnxkuqsd6wjwwx.onion:8333 -hgh3azn3eesddvcg.onion:8333 -hhyxu6bwkjefejoz.onion:8333 -hizn6rmofsg3upmn.onion:8333 -hjqxxsy2osemfvev.onion:8333 -hkbp7mbgw6klls4s.onion:8333 -hlojuwiwbkoj4kdz.onion:8333 -hlzxsjr7ob3qzzqq.onion:8333 -hniuzplezebyhv7a.onion:8333 -hondewkj4s4rdcwf.onion:8333 -hql5nv6vhceid3bn.onion:8333 -hspjo7mqrre5gyxr.onion:8333 -hu64s2mdr3x7yxka.onion:8333 -hvwvq2swkqw3qvyo.onion:8333 -hwo2biyndrrvpl6f.onion:8333 -hzxj3dth3y2xt45o.onion:8333 -i3ufxuw3t7cxfdpq.onion:8333 -ia3n3q5u45gvpx7a.onion:8333 -icfgs3fctckd4yeo.onion:8333 -icpz6thqvdjcwlvb.onion:8333 -if32zo5u4mhdunfd.onion:8333 -ig4lguql6vxkbmmr.onion:8333 -ihhcr7fhczqdac4y.onion:8333 -ijm2tyxob7vkvazz.onion:8333 -ip3puuqghumfz5ww.onion:8333 -iq3ket72f3y2frpg.onion:8333 -iqagt5co4dt7h6hf.onion:8333 -iugw42ih6hprqr26.onion:8333 -ivf774v4t7k63i6d.onion:8333 -ivfacdf7cig2z2y2.onion:8333 -ivsxdwku5og2zj4l.onion:8333 -ixwgrhaklvu4g6o7.onion:8333 -iz56moo6mkp3g7xo.onion:8333 -j2cp5muw5j3lumcx.onion:8333 -j2lrkrwugldwewws.onion:8333 -j2qtmkd2dablssz4.onion:8333 -j5e2yuan57v2h5el.onion:8333 -j5jfrdthqt5g25xz.onion:8333 -j5lk2uv2bspfqxfk.onion:8333 -janvvzsmzcsj3fil.onion:8333 -jenn2tmyl3xxarmq.onion:8333 -jfoe5f2sczojfp32.onion:8333 -jgcgi6k2pxooi5q3.onion:8333 -jhana24s3dzkitzp.onion:8333 -jitgulb24mvfqrdg.onion:8333 -jjuvwbjfzljmn7t3.onion:8333 -jlcfomgr5xfexaif.onion:8333 -jlehs6ybb26qlnna.onion:8333 -jljzz4tmbqrxq3q5.onion:8333 -joc4oqceedkg77vf.onion:8333 -jr5y6njubcbv6g37.onion:8333 -jroaos6la4vieho4.onion:8333 -jsmphgkay7iihbkr.onion:8333 -jtksnokusbzms7wl.onion:8333 -ju5duo3r6p6diznc.onion:8333 -jw6zymxcnebahuuj.onion:8333 -jxalvhf7w7wevqzw.onion:8333 -jyzhe3ig44ickysb.onion:8333 -jze6ukn4idrh44eo.onion:8333 -k4glotlxnmttb6ct.onion:8333 -k7uy3iwmvguzygd2.onion:8333 -kl23ofag3ukb6hxl.onion:8333 -kokt2qr6d4pmyb2d.onion:8333 -kpalu3h5ydkoaivs.onion:8333 -krdpbdvtqw5c5lee.onion:8333 -kriw6kzjzarzgb3g.onion:8333 -krp2thcmwrpsoue6.onion:8333 -kvyvdwjwtae5mo77.onion:8333 -kyrxri5rbr6ipurs.onion:8333 -kz3oxg7745dxt62q.onion:8333 -l3w5fcki2wbro2qb.onion:8333 -l44bisuxhh7reb5q.onion:8333 -l565g523emjebusj.onion:8333 -l6w5kdeigwsgnf5t.onion:8333 -l7a4emryfxkjgmmb.onion:8333 -l7sloscjqqbifcsw.onion:8333 -laafjqvtog7djfl2.onion:8333 -lah676kxbgbgw3u2.onion:8333 -lbq2a7pnpmviw2qo.onion:8333 -lc4wnpql27vymi35.onion:8333 -ldoffbfpk3j6c7y7.onion:8333 -lehpmglkivobq2qo.onion:8333 -lgewpjz7ie7daqqr.onion:8333 -lgkvbvro67jomosw.onion:8333 -liw5z4ngic6b7vnv.onion:8333 -ljs7gwrmmza6q6ga.onion:8333 -lmvax3e6awaxvhqi.onion:8333 -lrz77dwf7yq4cgnt.onion:8333 -lva54pnbq2nsmjyr.onion:8333 -lxc2uphxyyxflhnf.onion:8333 -lyjybdr4hmj3bqab.onion:8333 -lz2zlnmyynwtgwf2.onion:8333 -m6hcnpikimyh37yp.onion:8333 -md635omjnrgheed3.onion:8333 -mdb3oupwf4f2qyjb.onion:8333 -me6d4esx7ohdnxne.onion:8333 -mecfkik5ci47wckj.onion:8333 -mfrvevn7w6rwsp4r.onion:8333 -mimuutlew5srtduk.onion:8333 -mnysk3izxvra3huv.onion:8333 -mqu6gqtrhm6xzwwh.onion:8333 -mwuc6vom4ngijtb3.onion:8333 -mxdtrjhe2yfsx3pg.onion:8333 -n4ibet4piscv22nj.onion:8333 -n6d46vbzx43bevlb.onion:8333 -n6t6kfgzlvozxhfm.onion:8333 -n7rrochwerf2qxze.onion:8333 -ncsdiqmnxhnnjbsz.onion:8333 -nitxw3ilffngpumv.onion:8333 -njlsvubildehluwr.onion:8333 -njslfsivyyhixbsp.onion:8333 -nkf5e6b7pl4jfd4a.onion:8333 -nkppsb3t3ducje6m.onion:8333 -nlfwyqksmeqe45zz.onion:8333 -nlyjmpcmpaz5b4aa.onion:8333 -nnmv7z65k65mcesr.onion:8333 -nrrfwdmrm3imuebn.onion:8333 -nrrmkgmulpgsbwlt.onion:8333 -nw4h7leckut7eapv.onion:8333 -nwky3wd3ihoidvb5.onion:8333 -ny4kkemmmqv4lptm.onion:8333 -o25wkcw7eorg2toi.onion:8333 -o2gumvbkw6pm45cf.onion:8333 -o4yjshdwlbshylqw.onion:8333 -ofx4qgw6lppnvtgv.onion:8333 -oketipl4gndqcaus.onion:8333 -oq5q4qrqijr2kpun.onion:8333 -oqw3mfoiobqcklxh.onion:8333 -orsy2v63ecrmdj55.onion:8333 -ot4tzmznyimmlszk.onion:8333 -owk6c2jfthwkyahe.onion:8333 -oy7ss3hm2okx4tun.onion:8333 -p2pc6wbaepvdi6ce.onion:8333 -p2x24gdhasmgcl5j.onion:8333 -p6couujr2ndhllv3.onion:8333 -pa7dw5bln5lqmu53.onion:8333 -pasmchtoooj2kchd.onion:8333 -pdapkkhk6pbcy2tj.onion:8333 -peh5ajouuw6mw4sr.onion:8333 -pkuuc5pwl5xygwhr.onion:8333 -pq4wjl7vg7tsfycc.onion:8333 -ptbwqhusps5qieql.onion:8333 -ptwpbwyj5lnyew2f.onion:8333 -pu7w3jfyrzp7sxsi.onion:8333 -pwylbyvfuc62hhvx.onion:8333 -q2fhnnyt5b2ayvce.onion:8333 -q3i3apuionbazmfe.onion:8333 -qd6fcpu3pvbf2y3x.onion:8333 -qfewv3y7a3p4i3bd.onion:8333 -qhytdttflhbc4rsh.onion:8333 -qkn35rb3x2gxbwq4.onion:8333 -qlvlexs7pwac2f4b.onion:8333 -qogcqirtuta6rlxg.onion:8333 -qrzqfxkhrmu5v5ro.onion:8333 -qsyjasq46b2syiys.onion:8333 -quu4b2zjbnr2ue4y.onion:8333 -quycfj2wenz6bfyd.onion:8333 -qvdy3cmocnlv5v7c.onion:8333 -qvwhpqygan2xky5h.onion:8333 -qyutwc26ullujafb.onion:8333 -r45qg2d6iwfdhqwl.onion:8333 -r4xudr6u4r5nyga4.onion:8333 -r6apa5ssujxbwd34.onion:8333 -r6z2gcsu37k3gaah.onion:8333 -rbrjgfcca6v5b7yo.onion:8333 -rcifxibawqt6rxzz.onion:8333 -rdo3xctk3zkzjvln.onion:8333 -rdvlepy6ghgpapzo.onion:8333 -recs3a27chv2lg65.onion:8333 -rfmbiy5vztvn6hyn.onion:8333 -rli5lbje4k77inzw.onion:8333 -roqwnmepcj453vfh.onion:8333 -rpbnx54qniivrmh3.onion:8333 -rsvvogqdlijp77hv.onion:8333 -rwm5d4hg3hc77kdt.onion:8333 -s3yelkvc5f5xeysw.onion:8333 -s6rx52hitmpp4lge.onion:8333 -sa6m3rvycipgemky.onion:8333 -savebeesmkivmfbo.onion:8333 -sbyjr5npk2mlmfw7.onion:8333 -serwj42jme5xhhmw.onion:8333 -sg4vmubv3djrzvuh.onion:8333 -shsgksluz6jkgp6g.onion:8333 -sjyzmwwu6diiit3r.onion:8333 -sk3en3reudg3sdg5.onion:8333 -skoifp4oj7l4osu5.onion:8333 -sle2caplkln33e7y.onion:8333 -smdd7q7gonajdmjq.onion:8333 -spmhuxjb2cd7leun.onion:8333 -srkgyv5edn2pa7il.onion:8333 -sslnjjhnmwllysv4.onion:8333 -su66ygras6rkdtnl.onion:8333 -sundvmbjrtgdfahx.onion:8333 -svd65k5jpal2p3lt.onion:8333 -svua5hiqluw7o2sw.onion:8333 -sxqjubmum4rmfgpu.onion:8333 -t245vi742ti3tnka.onion:8333 -t4fbovvgzpnimd2p.onion:8333 -t4l4wv3erkhpde2p.onion:8333 -t5qchwbr6u5v2agk.onion:8333 -t7jlaj6ggyx7s5vy.onion:8333 -ta6sjeqyb27f4n4a.onion:8333 -tav7utpw4pfy7j6k.onion:8333 -taxg5z2sxfm5c4d6.onion:8333 -tekwvnbodbzrlufs.onion:8333 -tg4uwrjmtr2jlbjy.onion:8333 -th4cjvffjtw6vomu.onion:8333 -th6fxymtwnfifqeu.onion:8333 -thtchhl25u26nglq.onion:8333 -tiiah7csuoklcvi6.onion:8333 -tk63x5fk3337z3ud.onion:8333 -tkgootat6cqn7vyy.onion:8333 -tnj565wwqz5wpjvs.onion:8333 -ts6qx37mmpu6nj5y.onion:8333 -ttjisvxydgbtp56f.onion:8333 -twn54v7ra2xjgd55.onion:8333 -txem5meug24g2ezd.onion:8333 -tyiunn36lmfcq5lr.onion:8333 -tyv56xs6g6ndzqux.onion:8333 -u47f3hxwq65sgs4o.onion:8333 -u4r7fnholrdwwlni.onion:8333 -u556ofb3myarafwn.onion:8333 -u5q3gbz4qpz4wvlr.onion:8333 -uakly3ydrevvpxwi.onion:8333 -ug6hapi4qtekzc7v.onion:8333 -ui553qotd6ron3rf.onion:8333 -uir7f3wltoka6bbb.onion:8333 -ukrjjhwodl44wmof.onion:8333 -ul5gm2ixy7kqdfwg.onion:8333 -undd7rsj4pen3wo4.onion:8333 -uorwpzfehtykrg43.onion:8333 -uovsp2yltnaojq6l.onion:8333 -usazmdcs32ny24dy.onion:8333 -usazs7glm7geyxkl.onion:8333 -uss2kedg7qkwgdr5.onion:8333 -utgyrvw75wv2nymi.onion:8333 -uzwacms7kyzhehbl.onion:8333 -v2kdcetvslmdfcwr.onion:8333 -v5lhnzzv6nngfg5d.onion:8333 -vc44gb4veppobrt3.onion:8333 -vfwyhju43wxhzvux.onion:8333 -vgujufk53lqyolio.onion:8333 -vheejqq2v5dkb4xr.onion:8333 -vj64edev4jnqfdsb.onion:8333 -vmai5uigezr2khkj.onion:8333 -vmuykd7sxbmi7w57.onion:8333 -vomeacttinx3mpml.onion:8333 -vpow2xofg3fwzsdq.onion:8333 -vsawli4l5ifxdzaw.onion:8333 -vunubqkfms7sifok.onion:8333 -vuombnevwul4bqsb.onion:8333 -vxcpvdng65aefz6t.onion:8333 -vyxoizdzavp3obau.onion:8333 -wbeon2ci7lfio6ay.onion:8333 -wbwevew62mgsrrdz.onion:8333 -wfaydlg6zyfzjcu5.onion:8333 -wfz56s5lyn5dysez.onion:8333 -wg3mq4ugyy2gx32b.onion:8333 -whky54bctkf2n4p3.onion:8333 -whmjanqoyzizzc4t.onion:8333 -wlhou2wxgqyi3x3f.onion:8333 -wlvkfrplfiioz22o.onion:8333 -x3ngb3va7dovuenw.onion:8333 -x57x62bmmnylvo7r.onion:8333 -xgvm57mhgv564dka.onion:8333 -xhs3glfwnwiumivn.onion:8333 -xje5fwvyfdue2u6k.onion:8333 -xlgubgyly2blvsg5.onion:8333 -xnlu3tvakngy7tkp.onion:8333 -xo5marilhuyo7but.onion:8333 -xsaaxihdygnwxrix.onion:8333 -xu5mlugdsmzfkvzh.onion:8333 -xvrxqcptqvieedb2.onion:8333 -xwzhrrygftq3q4w4.onion:8333 -y4swmsaxdcos2bnu.onion:8333 -y5tl4lqi365pplud.onion:8333 -y5wzeqyaets5na6t.onion:8333 -y73qk2mzkjkhoky7.onion:8333 -y7oz3ydnvib4xhbb.onion:8333 -yah7qgfqqrteoche.onion:8333 -yba4brm555denlt7.onion:8333 -ygeqkg4inplsace3.onion:8333 -yjhnfu75lazbi34h.onion:8333 -yjw7kqapxx5vggoj.onion:8333 -ym7inmovbrna4gco.onion:8333 -yq5cusnuokscy64z.onion:8333 -yrcaioqrqrdwokqt.onion:8333 -yrcr7pgjuazad254.onion:8333 -yrksvon3tmvoohdv.onion:8333 -ytpus4vx5w7j6wp2.onion:8333 -ytqcigk2hhdl45ho.onion:8333 -yxojl3xmjus3dik2.onion:8333 -yzdqdsqx4fdung6w.onion:8333 -z33nukt7ngik3cpe.onion:8333 -z3ywbadw46ndnxgh.onion:8333 -z6mbqq7llxlrn4kq.onion:8333 -zb3lrcksn4rzhzje.onion:8333 -ze7odp7pzarjplsr.onion:8333 -zgbmhtbja4fy2373.onion:8333 -zh7hvalcgvjpoaqm.onion:8333 -ziztvxehmj5mehpg.onion:8333 -zjii3yecdrmq73y3.onion:8333 -zkrwmgjuvsza6ye2.onion:8333 -zoz2aopwi3wfuqwg.onion:8333 -ztdcfnh46773bivu.onion:8333 -zuxhc6d3nwpgc4af.onion:8333 -zuytrfevzjcpizli.onion:8333 -zvq6dpt3i2ofdp3g.onion:8333 -zwwm6ga7u2hqe2sd.onion:8333 -zyqb4lenfspntj5m.onion:8333 # manually added 2021-03 for minimal torv3 bootstrap support 2g5qfdkn2vvcbqhzcyvyiitg4ceukybxklraxjnu7atlhd22gdwywaid.onion:8333 diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 6b3b293140..f879d176f5 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -26,7 +26,7 @@ $(package)_config_libraries=filesystem,system,test $(package)_cxxflags=-std=c++17 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC $(package)_cxxflags_android=-fPIC -$(package)_cxxflags_darwin=-fcf-protection=full +$(package)_cxxflags_x86_64_darwin=-fcf-protection=full endef define $(package)_preprocess_cmds diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index d23a64923b..52df26eb50 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,22 +1,22 @@ PACKAGE=qt -$(package)_version=5.12.10 +$(package)_version=5.12.11 $(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules $(package)_suffix=everywhere-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=8088f174e6d28e779516c083b6087b6a9e3c8322b4bc161fd1b54195e3c86940 +$(package)_sha256_hash=1c1b4e33137ca77881074c140d54c3c9747e845a31338cfe8680f171f0bc3a39 $(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon $(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch $(package)_patches+= fix_android_qmake_conf.patch fix_android_jni_static.patch dont_hardcode_pwd.patch $(package)_patches+= drop_lrelease_dependency.patch no_sdk_version_check.patch $(package)_patches+= fix_lib_paths.patch fix_android_pch.patch -$(package)_patches+= fix_bigsur_drawing.patch qtbase-moc-ignore-gcc-macro.patch +$(package)_patches+= qtbase-moc-ignore-gcc-macro.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=e1de58ed108b7e0a138815ea60fd46a2c4e1fc31396a707e5630e92de79c53de +$(package)_qttranslations_sha256_hash=577b0668a777eb2b451c61e8d026d79285371597ce9df06b6dee6c814164b7c3 $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=b0cfa6e7aac41b7c61fc59acc04843d7a98f9e1840370611751bcfc1834a636c +$(package)_qttools_sha256_hash=98b2aaca230458f65996f3534fd471d2ffd038dd58ac997c0589c06dc2385b4f $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) @@ -126,7 +126,7 @@ $(package)_config_opts_darwin += -device-option XCODE_VERSION=$(XCODE_VERSION) endif # for macOS on Apple Silicon (ARM) see https://bugreports.qt.io/browse/QTBUG-85279 -$(package)_config_opts_arm_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS=arm64 +$(package)_config_opts_aarch64_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS=arm64 $(package)_config_opts_linux = -qt-xcb $(package)_config_opts_linux += -no-xcb-xlib @@ -175,8 +175,6 @@ $(package)_config_opts_aarch64_android += -android-arch arm64-v8a $(package)_config_opts_armv7a_android += -android-arch armeabi-v7a $(package)_config_opts_x86_64_android += -android-arch x86_64 $(package)_config_opts_i686_android += -android-arch i686 - -$(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 endef define $(package)_fetch_cmds @@ -232,7 +230,6 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_bigsur_drawing.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch index f891da6ddf..a186aeb8f6 100644 --- a/depends/patches/qt/fix_android_jni_static.patch +++ b/depends/patches/qt/fix_android_jni_static.patch @@ -1,6 +1,6 @@ --- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp +++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp -@@ -897,6 +897,14 @@ +@@ -898,6 +898,14 @@ __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } diff --git a/depends/patches/qt/fix_bigsur_drawing.patch b/depends/patches/qt/fix_bigsur_drawing.patch deleted file mode 100644 index 98c0c6be30..0000000000 --- a/depends/patches/qt/fix_bigsur_drawing.patch +++ /dev/null @@ -1,31 +0,0 @@ -Fix GUI stuck on Big Sur - -See: - - https://github.com/bitcoin-core/gui/issues/249 - - https://github.com/bitcoin/bitcoin/pull/21495 - - https://bugreports.qt.io/browse/QTBUG-87014 - -We should be able to drop this once we are using one of the following versions: - - Qt 5.12.11 or later, see upstream commit: c5d904639dbd690a36306e2b455610029704d821 - - Qt 5.15.3 or later, see upstream commit: 2cae34354bd41ae286258c7a6b3653b746e786ae - ---- a/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm -+++ b/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm -@@ -95,8 +95,15 @@ - // by AppKit at a point where we've already set up other parts of the platform plugin - // based on the presence of layers or not. Once we've rewritten these parts to support - // dynamically picking up layer enablement we can let AppKit do its thing. -- return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave -- && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave; -+ -+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSBigSur) -+ return true; // Big Sur always enables layer-backing, regardless of SDK -+ -+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave -+ && QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave) -+ return true; // Mojave and Catalina enable layers based on the app's SDK -+ -+ return false; // Prior versions needed explicitly enabled layer backing - } - - - (BOOL)layerExplicitlyRequested diff --git a/doc/README.md b/doc/README.md index f32600d009..c629c2ccfa 100644 --- a/doc/README.md +++ b/doc/README.md @@ -30,6 +30,7 @@ Drag Bitcoin Core to your applications folder, and then run Bitcoin Core. * See the documentation at the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page) for help and more information. +* Ask for help on the [Bitcoin StackExchange](https://bitcoin.stackexchange.com) * Ask for help on [#bitcoin](https://webchat.freenode.net/#bitcoin) on Freenode. If you don't have an IRC client, use [webchat here](https://webchat.freenode.net/#bitcoin). * Ask for help on the [BitcoinTalk](https://bitcointalk.org/) forums, in the [Technical Support board](https://bitcointalk.org/index.php?board=4.0). @@ -67,7 +68,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th ### Resources * Discuss on the [BitcoinTalk](https://bitcointalk.org/) forums, in the [Development & Technical Discussion board](https://bitcointalk.org/index.php?board=6.0). -* Discuss project-specific development on #bitcoin-core-dev on Freenode. If you don't have an IRC client, use [webchat here](https://webchat.freenode.net/#bitcoin-core-dev). +* Discuss project-specific development on #bitcoin-core-dev on Libera Chat. If you don't have an IRC client, use [webchat here](https://web.libera.chat/#bitcoin-core-dev). * Discuss general Bitcoin development on #bitcoin-dev on Freenode. If you don't have an IRC client, use [webchat here](https://webchat.freenode.net/#bitcoin-dev). ### Miscellaneous diff --git a/doc/build-windows.md b/doc/build-windows.md index 0e92a8aeea..f88b9739de 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -81,9 +81,26 @@ The first step is to install the mingw-w64 cross-compilation tool chain: sudo apt install g++-mingw-w64-x86-64 -Ubuntu Bionic 18.04 <sup>[1](#footnote1)</sup>: +Next, set the default `mingw32 g++` compiler option to POSIX<sup>[1](#footnote1)</sup>: - sudo update-alternatives --config x86_64-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix. +``` +sudo update-alternatives --config x86_64-w64-mingw32-g++ +``` + +After running the above command, you should see output similar to that below. +Choose the option that ends with `posix`. + +``` +There are 2 choices for the alternative x86_64-w64-mingw32-g++ (providing /usr/bin/x86_64-w64-mingw32-g++). + + Selection Path Priority Status +------------------------------------------------------------ + 0 /usr/bin/x86_64-w64-mingw32-g++-win32 60 auto mode +* 1 /usr/bin/x86_64-w64-mingw32-g++-posix 30 manual mode + 2 /usr/bin/x86_64-w64-mingw32-g++-win32 60 manual mode + +Press <enter> to keep the current choice[*], or type selection number: +``` Once the toolchain is installed the build steps are common: diff --git a/doc/dependencies.md b/doc/dependencies.md index 854ff7f52d..9754952221 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -21,7 +21,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct | PCRE | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) | | Python (tests) | | [3.6](https://www.python.org/downloads) | | | | | qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | | -| Qt | [5.12.10](https://download.qt.io/official_releases/qt/) | [5.9.5](https://github.com/bitcoin/bitcoin/issues/20104) | No | | | +| Qt | [5.12.11](https://download.qt.io/official_releases/qt/) | [5.9.5](https://github.com/bitcoin/bitcoin/issues/20104) | No | | | | SQLite | [3.32.1](https://sqlite.org/download.html) | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | | | | | XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Linux only) | | xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Linux only) | diff --git a/doc/descriptors.md b/doc/descriptors.md index c4fc2a66bf..e27ff87546 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -30,6 +30,7 @@ Output descriptors currently support: - Pay-to-witness-pubkey-hash scripts (P2WPKH), through the `wpkh` function. - Pay-to-script-hash scripts (P2SH), through the `sh` function. - Pay-to-witness-script-hash scripts (P2WSH), through the `wsh` function. +- Pay-to-taproot outputs (P2TR), through the `tr` function. - Multisig scripts, through the `multi` function. - Multisig scripts where the public keys are sorted lexicographically, through the `sortedmulti` function. - Any type of supported address through the `addr` function. @@ -54,6 +55,7 @@ Output descriptors currently support: - `pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)` describes a set of P2PKH outputs, but additionally specifies that the specified xpub is a child of a master with fingerprint `d34db33f`, and derived using path `44'/0'/0'`. - `wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where the first multisig key is the *1/0/`i`* child of the first specified xpub and the second multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default). - `wsh(sortedmulti(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where one multisig key is the *1/0/`i`* child of the first specified xpub and the other multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default). The order of public keys in the resulting witnessScripts is determined by the lexicographic order of the public keys at that index. +- `tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,{pk(fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),pk(e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)})` describes a P2TR output with the `c6...` x-only pubkey as internal key, and two script paths. ## Reference @@ -61,13 +63,14 @@ Descriptors consist of several types of expressions. The top level expression is `SCRIPT` expressions: - `sh(SCRIPT)` (top level only): P2SH embed the argument. -- `wsh(SCRIPT)` (not inside another 'wsh'): P2WSH embed the argument. +- `wsh(SCRIPT)` (top level or inside `sh` only): P2WSH embed the argument. - `pk(KEY)` (anywhere): P2PK output for the given public key. -- `pkh(KEY)` (anywhere): P2PKH output for the given public key (use `addr` if you only know the pubkey hash). -- `wpkh(KEY)` (not inside `wsh`): P2WPKH output for the given compressed pubkey. +- `pkh(KEY)` (not inside `tr`): P2PKH output for the given public key (use `addr` if you only know the pubkey hash). +- `wpkh(KEY)` (top level or inside `sh` only): P2WPKH output for the given compressed pubkey. - `combo(KEY)` (top level only): an alias for the collection of `pk(KEY)` and `pkh(KEY)`. If the key is compressed, it also includes `wpkh(KEY)` and `sh(wpkh(KEY))`. -- `multi(k,KEY_1,KEY_2,...,KEY_n)` (anywhere): k-of-n multisig script. -- `sortedmulti(k,KEY_1,KEY_2,...,KEY_n)` (anywhere): k-of-n multisig script with keys sorted lexicographically in the resulting script. +- `multi(k,KEY_1,KEY_2,...,KEY_n)` (not inside `tr`): k-of-n multisig script. +- `sortedmulti(k,KEY_1,KEY_2,...,KEY_n)` (not inside `tr`): k-of-n multisig script with keys sorted lexicographically in the resulting script. +- `tr(KEY)` or `tr(KEY,TREE)` (top level only): P2TR output with the specified key as internal key, and optionally a tree of script paths. - `addr(ADDR)` (top level only): the script which ADDR expands to. - `raw(HEX)` (top level only): the script whose hex encoding is HEX. @@ -80,12 +83,17 @@ Descriptors consist of several types of expressions. The top level expression is - Followed by the actual key, which is either: - Hex encoded public keys (either 66 characters starting with `02` or `03` for a compressed pubkey, or 130 characters starting with `04` for an uncompressed pubkey). - Inside `wpkh` and `wsh`, only compressed public keys are permitted. + - Inside `tr`, x-only pubkeys are also permitted (64 hex characters). - [WIF](https://en.bitcoin.it/wiki/Wallet_import_format) encoded private keys may be specified instead of the corresponding public key, with the same meaning. - `xpub` encoded extended public key or `xprv` encoded extended private key (as defined in [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)). - Followed by zero or more `/NUM` unhardened and `/NUM'` hardened BIP32 derivation steps. - Optionally followed by a single `/*` or `/*'` final step to denote all (direct) unhardened or hardened children. - The usage of hardened derivation steps requires providing the private key. +`TREE` expressions: +- any `SCRIPT` expression +- An open brace `{`, a `TREE` expression, a comma `,`, a `TREE` expression, and a closing brace `}` + (Anywhere a `'` suffix is permitted to denote hardened derivation, the suffix `h` can be used instead.) `ADDR` expressions are any type of supported address: diff --git a/doc/release-process.md b/doc/release-process.md index 84b208a0d8..3ead1181b9 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -373,9 +373,7 @@ bitcoin.org (see below for bitcoin.org update instructions). - Bitcoin Core announcements list https://bitcoincore.org/en/list/announcements/join/ - - Update title of #bitcoin on Freenode IRC - - - Optionally twitter, reddit /r/Bitcoin, ... but this will usually sort out itself + - Bitcoin Core Twitter https://twitter.com/bitcoincoreorg - Celebrate diff --git a/doc/translation_process.md b/doc/translation_process.md index 785bb0047b..f132693264 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -102,6 +102,5 @@ To create a new language template, you will need to edit the languages manifest **Note:** that the language translation file **must end in `.qm`** (the compiled extension), and not `.ts`. ### Questions and general assistance -The Bitcoin-Core translation maintainers include *tcatm, seone, Diapolo, wumpus and luke-jr*. You can find them, and others, in the Freenode IRC chatroom - `irc.freenode.net #bitcoin-core-dev`. If you are a translator, you should also subscribe to the mailing list, https://groups.google.com/forum/#!forum/bitcoin-translators. Announcements will be posted during application pre-releases to notify translators to check for updates. diff --git a/share/examples/bitcoin.conf b/share/examples/bitcoin.conf index 318b48bf2e..4a947001fa 100644 --- a/share/examples/bitcoin.conf +++ b/share/examples/bitcoin.conf @@ -71,6 +71,12 @@ # configuration option or the addnode RPC, which have a separate limit of 8 connections. #maxconnections= +# Maximum upload bandwidth target in MiB per day (e.g. 'maxuploadtarget=1024' is 1 GiB per day). +# This limits the upload bandwidth for those with bandwidth limits. 0 = no limit (default: 0). +# -maxuploadtarget does not apply to peers with 'download' permission. +# For more information on reducing bandwidth utilization, see: doc/reduce-traffic.md. +#maxuploadtarget= + # # JSON-RPC options (for controlling a running Bitcoin/bitcoind process) # diff --git a/src/Makefile.am b/src/Makefile.am index 80c142009c..66cb7cec2a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -285,10 +285,13 @@ BITCOIN_CORE_H = \ wallet/fees.h \ wallet/ismine.h \ wallet/load.h \ + wallet/receive.h \ wallet/rpcwallet.h \ wallet/salvage.h \ wallet/scriptpubkeyman.h \ + wallet/spend.h \ wallet/sqlite.h \ + wallet/transaction.h \ wallet/wallet.h \ wallet/walletdb.h \ wallet/wallettool.h \ @@ -406,9 +409,12 @@ libbitcoin_wallet_a_SOURCES = \ wallet/fees.cpp \ wallet/interfaces.cpp \ wallet/load.cpp \ + wallet/receive.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/scriptpubkeyman.cpp \ + wallet/spend.cpp \ + wallet/transaction.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ wallet/walletutil.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 9ad66bc85b..a1821cafe3 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -365,12 +365,12 @@ translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCO $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) @cp -f $< $(@D)/temp_$(<F) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale $(@D)/temp_$(<F) > $@ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale --format-version 1 $(@D)/temp_$(<F) > $@ @rm $(@D)/temp_$(<F) $(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION) @test -f $(RCC) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin $< > $@ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin --format-version 1 $< > $@ CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno qt/temp_bitcoin_locale.qrc diff --git a/src/addrman.cpp b/src/addrman.cpp index ceab1689d7..14b412a038 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -36,7 +36,7 @@ int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std: int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const { - uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetCheapHash(); + uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash(); return hash1 % ADDRMAN_BUCKET_SIZE; } @@ -652,7 +652,7 @@ std::vector<bool> CAddrMan::DecodeAsmap(fs::path path) int length = ftell(filestr); LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length); fseek(filestr, 0, SEEK_SET); - char cur_byte; + uint8_t cur_byte; for (int i = 0; i < length; ++i) { file >> cur_byte; for (int bit = 0; bit < 8; ++bit) { diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index aa72981cb4..b4b33d115f 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -37,7 +37,7 @@ static void AssembleBlock(benchmark::Bench& bench) LOCK(::cs_main); // Required for ::AcceptToMemoryPool. for (const auto& txr : txs) { - const MempoolAcceptResult res = ::AcceptToMemoryPool(::ChainstateActive(), *test_setup->m_node.mempool, txr, false /* bypass_limits */); + const MempoolAcceptResult res = ::AcceptToMemoryPool(test_setup->m_node.chainman->ActiveChainstate(), *test_setup->m_node.mempool, txr, false /* bypass_limits */); assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID); } } diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index 25d1a2b56c..4f6e1122b8 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -25,7 +25,8 @@ static void DuplicateInputs(benchmark::Bench& bench) CMutableTransaction naughtyTx{}; LOCK(cs_main); - CBlockIndex* pindexPrev = ::ChainActive().Tip(); + assert(std::addressof(::ChainActive()) == std::addressof(testing_setup->m_node.chainman->ActiveChain())); + CBlockIndex* pindexPrev = testing_setup->m_node.chainman->ActiveChain().Tip(); assert(pindexPrev != nullptr); block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus()); block.nNonce = 0; diff --git a/src/bench/nanobench.h b/src/bench/nanobench.h index c5379e7fd4..030d6ebf6a 100644 --- a/src/bench/nanobench.h +++ b/src/bench/nanobench.h @@ -7,7 +7,7 @@ // // Licensed under the MIT License <http://opensource.org/licenses/MIT>. // SPDX-License-Identifier: MIT -// Copyright (c) 2019-2020 Martin Ankerl <martin.ankerl@gmail.com> +// Copyright (c) 2019-2021 Martin Ankerl <martin.ankerl@gmail.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,8 +32,8 @@ // see https://semver.org/ #define ANKERL_NANOBENCH_VERSION_MAJOR 4 // incompatible API changes -#define ANKERL_NANOBENCH_VERSION_MINOR 0 // backwards-compatible changes -#define ANKERL_NANOBENCH_VERSION_PATCH 0 // backwards-compatible bug fixes +#define ANKERL_NANOBENCH_VERSION_MINOR 3 // backwards-compatible changes +#define ANKERL_NANOBENCH_VERSION_PATCH 4 // backwards-compatible bug fixes /////////////////////////////////////////////////////////////////////////////////////////////////// // public facing api - as minimal as possible @@ -78,12 +78,20 @@ #if defined(ANKERL_NANOBENCH_LOG_ENABLED) # include <iostream> -# define ANKERL_NANOBENCH_LOG(x) std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl +# define ANKERL_NANOBENCH_LOG(x) \ + do { \ + std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl; \ + } while (0) #else -# define ANKERL_NANOBENCH_LOG(x) +# define ANKERL_NANOBENCH_LOG(x) \ + do { \ + } while (0) #endif -#if defined(__linux__) && !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS) +#if defined(__linux__) && defined(PERF_EVENT_IOC_ID) && defined(PERF_COUNT_HW_REF_CPU_CYCLES) && defined(PERF_FLAG_FD_CLOEXEC) && \ + !defined(ANKERL_NANOBENCH_DISABLE_PERF_COUNTERS) +// only enable perf counters on kernel 3.14 which seems to have all the necessary defines. The three PERF_... defines are not in +// kernel 2.6.32 (all others are). # define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 1 #else # define ANKERL_NANOBENCH_PRIVATE_PERF_COUNTERS() 0 @@ -173,7 +181,7 @@ class BigO; * `contextswitches`, `instructions`, `branchinstructions`, and `branchmisses`. All the measuers (except `iterations`) are * provided for a single iteration (so `elapsed` is the time a single iteration took). The following tags are available: * - * * `{{median(<name>>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`. + * * `{{median(<name>)}}` Calculate median of a measurement data set, e.g. `{{median(elapsed)}}`. * * * `{{average(<name>)}}` Average (mean) calculation. * @@ -181,10 +189,11 @@ class BigO; * metric for the variation of measurements. It is more robust to outliers than the * [Mean absolute percentage error (M-APE)](https://en.wikipedia.org/wiki/Mean_absolute_percentage_error). * @f[ - * \mathrm{medianAbsolutePercentError}(e) = \mathrm{median}\{| \frac{e_i - \mathrm{median}\{e\}}{e_i}| \} + * \mathrm{MdAPE}(e) = \mathrm{med}\{| \frac{e_i - \mathrm{med}\{e\}}{e_i}| \} * @f] - * E.g. for *elapsed*: First, @f$ \mathrm{median}\{elapsed\} @f$ is calculated. This is used to calculate the absolute percentage - * error to this median for each measurement, as in @f$ | \frac{e_i - \mathrm{median}\{e\}}{e_i}| @f$. All these results + * E.g. for *elapsed*: First, @f$ \mathrm{med}\{e\} @f$ calculates the median by sorting and then taking the middle element + * of all *elapsed* measurements. This is used to calculate the absolute percentage + * error to this median for each measurement, as in @f$ | \frac{e_i - \mathrm{med}\{e\}}{e_i}| @f$. All these results * are sorted, and the middle value is chosen as the median absolute percent error. * * This measurement is a bit hard to interpret, but it is very robust against outliers. E.g. a value of 5% means that half of the @@ -207,7 +216,7 @@ class BigO; * * * `{{#measurement}}` To access individual measurement results, open the begin tag for measurements. * - * * `{{elapsed}}` Average elapsed time per iteration, in seconds. + * * `{{elapsed}}` Average elapsed wall clock time per iteration, in seconds. * * * `{{iterations}}` Number of iterations in the measurement. The number of iterations will fluctuate due * to some applied randomness, to enhance accuracy. @@ -261,6 +270,7 @@ class BigO; * :cpp:func:`templates::csv() <ankerl::nanobench::templates::csv()>` * :cpp:func:`templates::json() <ankerl::nanobench::templates::json()>` * :cpp:func:`templates::htmlBoxplot() <ankerl::nanobench::templates::htmlBoxplot()>` + * :cpp:func:`templates::pyperf() <ankerl::nanobench::templates::pyperf()>` @endverbatim * @@ -269,6 +279,7 @@ class BigO; * @param out Output for the generated output. */ void render(char const* mustacheTemplate, Bench const& bench, std::ostream& out); +void render(std::string const& mustacheTemplate, Bench const& bench, std::ostream& out); /** * Same as render(char const* mustacheTemplate, Bench const& bench, std::ostream& out), but for when @@ -279,6 +290,7 @@ void render(char const* mustacheTemplate, Bench const& bench, std::ostream& out) * @param out Output for the generated output. */ void render(char const* mustacheTemplate, std::vector<Result> const& results, std::ostream& out); +void render(std::string const& mustacheTemplate, std::vector<Result> const& results, std::ostream& out); // Contains mustache-like templates namespace templates { @@ -297,7 +309,7 @@ char const* csv() noexcept; /*! @brief HTML output that uses plotly to generate an interactive boxplot chart. See the tutorial for an example output. - The output uses only the elapsed time, and displays each epoch as a single dot. + The output uses only the elapsed wall clock time, and displays each epoch as a single dot. @verbatim embed:rst See the tutorial at :ref:`tutorial-template-html` for an example. @endverbatim @@ -307,6 +319,14 @@ char const* csv() noexcept; char const* htmlBoxplot() noexcept; /*! + @brief Output in pyperf compatible JSON format, which can be used for more analyzations. + @verbatim embed:rst + See the tutorial at :ref:`tutorial-template-pyperf` for an example how to further analyze the output. + @endverbatim + */ +char const* pyperf() noexcept; + +/*! @brief Template to generate JSON data. The generated JSON data contains *all* data that has been generated. All times are as double values, in seconds. The output can get @@ -369,6 +389,8 @@ struct Config { uint64_t mEpochIterations{0}; // If not 0, run *exactly* these number of iterations per epoch. uint64_t mWarmup = 0; std::ostream* mOut = nullptr; + std::chrono::duration<double> mTimeUnit = std::chrono::nanoseconds{1}; + std::string mTimeUnitName = "ns"; bool mShowPerformanceCounters = true; bool mIsRelative = false; @@ -504,6 +526,7 @@ public: */ explicit Rng(uint64_t seed) noexcept; Rng(uint64_t x, uint64_t y) noexcept; + Rng(std::vector<uint64_t> const& data); /** * Creates a copy of the Rng, thus the copy provides exactly the same random sequence as the original. @@ -558,6 +581,14 @@ public: template <typename Container> void shuffle(Container& container) noexcept; + /** + * Extracts the full state of the generator, e.g. for serialization. For this RNG this is just 2 values, but to stay API compatible + * with future implementations that potentially use more state, we use a vector. + * + * @return Vector containing the full state: + */ + std::vector<uint64_t> state() const; + private: static constexpr uint64_t rotl(uint64_t x, unsigned k) noexcept; @@ -667,6 +698,19 @@ public: ANKERL_NANOBENCH(NODISCARD) std::string const& unit() const noexcept; /** + * @brief Sets the time unit to be used for the default output. + * + * Nanobench defaults to using ns (nanoseconds) as output in the markdown. For some benchmarks this is too coarse, so it is + * possible to configure this. E.g. use `timeUnit(1ms, "ms")` to show `ms/op` instead of `ns/op`. + * + * @param tu Time unit to display the results in, default is 1ns. + * @param tuName Name for the time unit, default is "ns" + */ + Bench& timeUnit(std::chrono::duration<double> const& tu, std::string const& tuName); + ANKERL_NANOBENCH(NODISCARD) std::string const& timeUnitName() const noexcept; + ANKERL_NANOBENCH(NODISCARD) std::chrono::duration<double> const& timeUnit() const noexcept; + + /** * @brief Set the output stream where the resulting markdown table will be printed to. * * The default is `&std::cout`. You can disable all output by setting `nullptr`. @@ -916,6 +960,7 @@ public: @endverbatim */ Bench& render(char const* templateContent, std::ostream& os); + Bench& render(std::string const& templateContent, std::ostream& os); Bench& config(Config const& benchmarkConfig); ANKERL_NANOBENCH(NODISCARD) Config const& config() const noexcept; @@ -945,23 +990,24 @@ void doNotOptimizeAway(T const& val); #else -// see folly's Benchmark.h -template <typename T> -constexpr bool doNotOptimizeNeedsIndirect() { - using Decayed = typename std::decay<T>::type; - return !ANKERL_NANOBENCH_IS_TRIVIALLY_COPYABLE(Decayed) || sizeof(Decayed) > sizeof(long) || std::is_pointer<Decayed>::value; -} - +// These assembly magic is directly from what Google Benchmark is doing. I have previously used what facebook's folly was doing, but +// this seemd to have compilation problems in some cases. Google Benchmark seemed to be the most well tested anyways. +// see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307 template <typename T> -typename std::enable_if<!doNotOptimizeNeedsIndirect<T>()>::type doNotOptimizeAway(T const& val) { +void doNotOptimizeAway(T const& val) { // NOLINTNEXTLINE(hicpp-no-assembler) - asm volatile("" ::"r"(val)); + asm volatile("" : : "r,m"(val) : "memory"); } template <typename T> -typename std::enable_if<doNotOptimizeNeedsIndirect<T>()>::type doNotOptimizeAway(T const& val) { +void doNotOptimizeAway(T& val) { +# if defined(__clang__) + // NOLINTNEXTLINE(hicpp-no-assembler) + asm volatile("" : "+r,m"(val) : : "memory"); +# else // NOLINTNEXTLINE(hicpp-no-assembler) - asm volatile("" ::"m"(val) : "memory"); + asm volatile("" : "+m,r"(val) : : "memory"); +# endif } #endif @@ -1067,7 +1113,7 @@ constexpr uint64_t(Rng::max)() { return (std::numeric_limits<uint64_t>::max)(); } -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") uint64_t Rng::operator()() noexcept { auto x = mX; @@ -1077,7 +1123,7 @@ uint64_t Rng::operator()() noexcept { return x; } -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") uint32_t Rng::bounded(uint32_t range) noexcept { uint64_t r32 = static_cast<uint32_t>(operator()()); auto multiresult = r32 * range; @@ -1103,6 +1149,7 @@ void Rng::shuffle(Container& container) noexcept { } } +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") constexpr uint64_t Rng::rotl(uint64_t x, unsigned k) noexcept { return (x << k) | (x >> (64U - k)); } @@ -1306,6 +1353,30 @@ char const* htmlBoxplot() noexcept { </html>)DELIM"; } +char const* pyperf() noexcept { + return R"DELIM({ + "benchmarks": [ + { + "runs": [ + { + "values": [ +{{#measurement}} {{elapsed}}{{^-last}}, +{{/last}}{{/measurement}} + ] + } + ] + } + ], + "metadata": { + "loops": {{sum(iterations)}}, + "inner_loops": {{batch}}, + "name": "{{title}}", + "unit": "second" + }, + "version": "1.0" +})DELIM"; +} + char const* json() noexcept { return R"DELIM({ "results": [ @@ -1410,6 +1481,7 @@ static std::vector<Node> parseMustacheTemplate(char const** tpl) { } static bool generateFirstLast(Node const& n, size_t idx, size_t size, std::ostream& out) { + ANKERL_NANOBENCH_LOG("n.type=" << static_cast<int>(n.type)); bool matchFirst = n == "-first"; bool matchLast = n == "-last"; if (!matchFirst && !matchLast) { @@ -1632,6 +1704,7 @@ namespace detail { char const* getEnv(char const* name); bool isEndlessRunning(std::string const& name); +bool isWarningsEnabled(); template <typename T> T parseFile(std::string const& filename); @@ -1770,25 +1843,49 @@ void render(char const* mustacheTemplate, std::vector<Result> const& results, st for (size_t i = 0; i < nbResults; ++i) { generateResult(n.children, i, results, out); } + } else if (n == "measurement") { + if (results.size() != 1) { + throw std::runtime_error( + "render: can only use section 'measurement' here if there is a single result, but there are " + + detail::fmt::to_s(results.size())); + } + // when we only have a single result, we can immediately go into its measurement. + auto const& r = results.front(); + for (size_t i = 0; i < r.size(); ++i) { + generateResultMeasurement(n.children, i, r, out); + } } else { - throw std::runtime_error("unknown section '" + std::string(n.begin, n.end) + "'"); + throw std::runtime_error("render: unknown section '" + std::string(n.begin, n.end) + "'"); } break; case templates::Node::Type::tag: - // This just uses the last result's config. - if (!generateConfigTag(n, results.back().config(), out)) { - throw std::runtime_error("unknown tag '" + std::string(n.begin, n.end) + "'"); + if (results.size() == 1) { + // result & config are both supported there + generateResultTag(n, results.front(), out); + } else { + // This just uses the last result's config. + if (!generateConfigTag(n, results.back().config(), out)) { + throw std::runtime_error("unknown tag '" + std::string(n.begin, n.end) + "'"); + } } break; } } } +void render(std::string const& mustacheTemplate, std::vector<Result> const& results, std::ostream& out) { + render(mustacheTemplate.c_str(), results, out); +} + void render(char const* mustacheTemplate, const Bench& bench, std::ostream& out) { render(mustacheTemplate, bench.results(), out); } +void render(std::string const& mustacheTemplate, const Bench& bench, std::ostream& out) { + render(mustacheTemplate.c_str(), bench.results(), out); +} + namespace detail { PerformanceCounters& performanceCounters() { @@ -1837,6 +1934,12 @@ bool isEndlessRunning(std::string const& name) { return nullptr != endless && endless == name; } +// True when environment variable NANOBENCH_SUPPRESS_WARNINGS is either not set at all, or set to "0" +bool isWarningsEnabled() { + auto suppression = getEnv("NANOBENCH_SUPPRESS_WARNINGS"); + return nullptr == suppression || suppression == std::string("0"); +} + void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector<std::string>& recommendations) { warnings.clear(); recommendations.clear(); @@ -1889,13 +1992,13 @@ void gatherStabilityInformation(std::vector<std::string>& warnings, std::vector< recommendations.emplace_back("Make sure you compile for Release"); } if (recommendPyPerf) { - recommendations.emplace_back("Use 'pyperf system tune' before benchmarking. See https://github.com/vstinner/pyperf"); + recommendations.emplace_back("Use 'pyperf system tune' before benchmarking. See https://github.com/psf/pyperf"); } } void printStabilityInformationOnce(std::ostream* outStream) { static bool shouldPrint = true; - if (shouldPrint && outStream) { + if (shouldPrint && outStream && isWarningsEnabled()) { auto& os = *outStream; shouldPrint = false; std::vector<std::string> warnings; @@ -1923,16 +2026,7 @@ uint64_t& singletonHeaderHash() noexcept { return sHeaderHash; } -ANKERL_NANOBENCH_NO_SANITIZE("integer") -inline uint64_t fnv1a(std::string const& str) noexcept { - auto val = UINT64_C(14695981039346656037); - for (auto c : str) { - val = (val ^ static_cast<uint8_t>(c)) * UINT64_C(1099511628211); - } - return val; -} - -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") inline uint64_t hash_combine(uint64_t seed, uint64_t val) { return seed ^ (val + UINT64_C(0x9e3779b9) + (seed << 6U) + (seed >> 2U)); } @@ -2010,7 +2104,7 @@ struct IterationLogic::Impl { return static_cast<uint64_t>(doubleNewIters + 0.5); } - ANKERL_NANOBENCH_NO_SANITIZE("integer") void upscale(std::chrono::nanoseconds elapsed) { + ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void upscale(std::chrono::nanoseconds elapsed) { if (elapsed * 10 < mTargetRuntimePerEpoch) { // we are far below the target runtime. Multiply iterations by 10 (with overflow check) if (mNumIters * 10 < mNumIters) { @@ -2108,7 +2202,8 @@ struct IterationLogic::Impl { columns.emplace_back(14, 0, "complexityN", "", mBench.complexityN()); } - columns.emplace_back(22, 2, "ns/" + mBench.unit(), "", 1e9 * rMedian / mBench.batch()); + columns.emplace_back(22, 2, mBench.timeUnitName() + "/" + mBench.unit(), "", + rMedian / (mBench.timeUnit().count() * mBench.batch())); columns.emplace_back(22, 2, mBench.unit() + "/s", "", rMedian <= 0.0 ? 0.0 : mBench.batch() / rMedian); double rErrorMedian = mResult.medianAbsolutePercentError(Result::Measure::elapsed); @@ -2140,16 +2235,19 @@ struct IterationLogic::Impl { } } - columns.emplace_back(12, 2, "total", "", mResult.sum(Result::Measure::elapsed)); + columns.emplace_back(12, 2, "total", "", mResult.sumProduct(Result::Measure::iterations, Result::Measure::elapsed)); // write everything auto& os = *mBench.output(); + // combine all elements that are relevant for printing the header uint64_t hash = 0; - hash = hash_combine(fnv1a(mBench.unit()), hash); - hash = hash_combine(fnv1a(mBench.title()), hash); - hash = hash_combine(mBench.relative(), hash); - hash = hash_combine(mBench.performanceCounters(), hash); + hash = hash_combine(std::hash<std::string>{}(mBench.unit()), hash); + hash = hash_combine(std::hash<std::string>{}(mBench.title()), hash); + hash = hash_combine(std::hash<std::string>{}(mBench.timeUnitName()), hash); + hash = hash_combine(std::hash<double>{}(mBench.timeUnit().count()), hash); + hash = hash_combine(std::hash<bool>{}(mBench.relative()), hash); + hash = hash_combine(std::hash<bool>{}(mBench.performanceCounters()), hash); if (hash != singletonHeaderHash()) { singletonHeaderHash() = hash; @@ -2177,7 +2275,7 @@ struct IterationLogic::Impl { os << col.value(); } os << "| "; - auto showUnstable = rErrorMedian >= 0.05; + auto showUnstable = isWarningsEnabled() && rErrorMedian >= 0.05; if (showUnstable) { os << ":wavy_dash: "; } @@ -2305,7 +2403,7 @@ public: } template <typename Op> - ANKERL_NANOBENCH_NO_SANITIZE("integer") + ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void calibrate(Op&& op) { // clear current calibration data, for (auto& v : mCalibratedOverhead) { @@ -2411,7 +2509,7 @@ bool LinuxPerformanceCounters::monitor(perf_hw_id hwId, LinuxPerformanceCounters } // overflow is ok, it's checked -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") void LinuxPerformanceCounters::updateResults(uint64_t numIters) { // clear old data for (auto& id_value : mIdToTarget) { @@ -2963,6 +3061,20 @@ std::string const& Bench::unit() const noexcept { return mConfig.mUnit; } +Bench& Bench::timeUnit(std::chrono::duration<double> const& tu, std::string const& tuName) { + mConfig.mTimeUnit = tu; + mConfig.mTimeUnitName = tuName; + return *this; +} + +std::string const& Bench::timeUnitName() const noexcept { + return mConfig.mTimeUnitName; +} + +std::chrono::duration<double> const& Bench::timeUnit() const noexcept { + return mConfig.mTimeUnit; +} + // If benchmarkTitle differs from currently set title, the stored results will be cleared. Bench& Bench::title(const char* benchmarkTitle) { if (benchmarkTitle != mConfig.mBenchmarkTitle) { @@ -3083,6 +3195,11 @@ Bench& Bench::render(char const* templateContent, std::ostream& os) { return *this; } +Bench& Bench::render(std::string const& templateContent, std::ostream& os) { + ::ankerl::nanobench::render(templateContent, *this, os); + return *this; +} + std::vector<BigO> Bench::complexityBigO() const { std::vector<BigO> bigOs; auto rangeMeasure = BigO::collectRangeMeasure(mResults); @@ -3119,7 +3236,7 @@ Rng::Rng() } while (mX == 0 && mY == 0); } -ANKERL_NANOBENCH_NO_SANITIZE("integer") +ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") uint64_t splitMix64(uint64_t& state) noexcept { uint64_t z = (state += UINT64_C(0x9e3779b97f4a7c15)); z = (z ^ (z >> 30U)) * UINT64_C(0xbf58476d1ce4e5b9); @@ -3145,6 +3262,24 @@ Rng Rng::copy() const noexcept { return Rng{mX, mY}; } +Rng::Rng(std::vector<uint64_t> const& data) + : mX(0) + , mY(0) { + if (data.size() != 2) { + throw std::runtime_error("ankerl::nanobench::Rng::Rng: needed exactly 2 entries in data, but got " + + detail::fmt::to_s(data.size())); + } + mX = data[0]; + mY = data[1]; +} + +std::vector<uint64_t> Rng::state() const { + std::vector<uint64_t> data(2); + data[0] = mX; + data[1] = mY; + return data; +} + BigO::RangeMeasure BigO::collectRangeMeasure(std::vector<Result> const& results) { BigO::RangeMeasure rangeMeasure; for (auto const& result : results) { diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 4a4710ea3a..c5840b2098 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -418,7 +418,7 @@ private: if (conn_type == "addr-fetch") return "addr"; return ""; } - const int64_t m_time_now{GetSystemTimeInSeconds()}; + const int64_t m_time_now{GetTimeSeconds()}; public: static constexpr int ID_PEERINFO = 0; diff --git a/src/chain.h b/src/chain.h index 04a5db5a17..84a3a4e1e7 100644 --- a/src/chain.h +++ b/src/chain.h @@ -182,7 +182,7 @@ public: //! //! Note: this value is modified to show BLOCK_OPT_WITNESS during UTXO snapshot //! load to avoid the block index being spuriously rewound. - //! @sa RewindBlockIndex + //! @sa NeedsRedownload //! @sa ActivateSnapshot uint32_t nStatus{0}; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1b71c4db43..fdaadeed4a 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -423,7 +423,7 @@ public: pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; nDefaultPort = 18444; - nPruneAfterHeight = gArgs.GetBoolArg("-fastprune", false) ? 100 : 1000; + nPruneAfterHeight = args.GetBoolArg("-fastprune", false) ? 100 : 1000; m_assumed_blockchain_size = 0; m_assumed_chain_state_size = 0; diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 994d420885..08587e2b37 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -659,518 +659,6 @@ static const uint8_t chainparams_seed_main[] = { 0x02,0x10,0x2a,0x0f,0xdf,0x00,0x00,0x00,0x02,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x20,0x8d, 0x02,0x10,0x2c,0x0f,0xf5,0x98,0x00,0x05,0x00,0x01,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, 0x02,0x10,0x2c,0x0f,0xfc,0xe8,0x00,0x00,0x04,0x00,0x0b,0x7c,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d, - 0x03,0x0a,0xd6,0xbc,0x4a,0x3c,0x6d,0x03,0xa9,0x4e,0x1f,0x55,0x20,0x8d, - 0x03,0x0a,0xd6,0x8f,0xf0,0xf8,0xbb,0x10,0x00,0x18,0x42,0x54,0x20,0x8d, - 0x03,0x0a,0xd6,0xec,0x32,0xc1,0x59,0x9c,0xd8,0x46,0xd5,0x48,0x20,0x8d, - 0x03,0x0a,0xd6,0xf0,0x8d,0x96,0x37,0xc3,0x27,0x61,0x9a,0x24,0x20,0x8d, - 0x03,0x0a,0xd0,0x12,0xe6,0xed,0x8e,0xc1,0x78,0x8d,0x1c,0x21,0x20,0x8d, - 0x03,0x0a,0xd0,0x4a,0xc5,0xbd,0x5d,0xe9,0xca,0x57,0xaf,0xc4,0x20,0x8d, - 0x03,0x0a,0xd0,0x94,0xc0,0x97,0xd2,0x32,0xed,0x81,0x92,0x67,0x20,0x8d, - 0x03,0x0a,0xd1,0xd5,0x49,0x23,0xa6,0x10,0x01,0x49,0xda,0x05,0x20,0x8d, - 0x03,0x0a,0xd2,0x2a,0x76,0x2c,0x37,0x09,0x9a,0xa1,0x61,0x4b,0x20,0x8d, - 0x03,0x0a,0xd3,0x19,0x77,0x50,0xf5,0xf3,0x48,0x17,0x59,0x50,0x20,0x8d, - 0x03,0x0a,0xd4,0x24,0xda,0xf8,0x97,0x6d,0x28,0x80,0x47,0xf9,0x20,0x8d, - 0x03,0x0a,0xd4,0x28,0x30,0x9d,0x6d,0xac,0x1e,0xb4,0x6e,0x59,0x20,0x8d, - 0x03,0x0a,0xd5,0x13,0x71,0x95,0xd5,0x2e,0x12,0xf6,0x0e,0x6e,0x20,0x8d, - 0x03,0x0a,0xd5,0xc6,0x62,0x50,0xb1,0x22,0xb6,0x4a,0x31,0x56,0x20,0x8d, - 0x03,0x0a,0xd5,0xc7,0x99,0x46,0x87,0x91,0x13,0xc9,0xc9,0x16,0x20,0x8d, - 0x03,0x0a,0xdf,0x22,0x06,0xea,0xce,0x87,0x08,0x09,0x32,0x52,0x20,0x8d, - 0x03,0x0a,0xdf,0xa1,0xf5,0x1c,0xe4,0x4e,0x97,0x71,0xee,0xc5,0x20,0x8d, - 0x03,0x0a,0xdf,0xf7,0x64,0x8e,0x4f,0xa3,0xbb,0xaa,0x4f,0x30,0x20,0x8d, - 0x03,0x0a,0xdf,0xfc,0xa5,0x92,0x7d,0xbc,0x03,0x13,0x69,0x35,0x20,0x8d, - 0x03,0x0a,0xdf,0xd5,0x61,0xfc,0xb7,0x73,0xff,0xef,0x2f,0xaa,0x20,0x8d, - 0x03,0x0a,0xd9,0x3b,0x3f,0x9e,0x1c,0x02,0xe7,0xd9,0xba,0xb7,0x20,0x8d, - 0x03,0x0a,0xd9,0x83,0x73,0x90,0x25,0x3b,0xa9,0x4b,0x18,0x5b,0x20,0x8d, - 0x03,0x0a,0xd9,0xcc,0x14,0xe4,0x9a,0x68,0x6d,0x8a,0x12,0xc5,0x20,0x8d, - 0x03,0x0a,0xda,0x29,0x4a,0xc4,0x7a,0xb0,0x0e,0x0d,0x0a,0xee,0x20,0x8d, - 0x03,0x0a,0xda,0x67,0x7a,0x24,0x60,0x45,0x8f,0xe4,0x2e,0x74,0x20,0x8d, - 0x03,0x0a,0xda,0xfa,0x48,0x68,0x74,0xfb,0x2b,0x21,0x27,0x80,0x20,0x8d, - 0x03,0x0a,0xdb,0x5c,0x56,0x99,0xb0,0x5c,0x08,0x43,0xb7,0xee,0x20,0x8d, - 0x03,0x0a,0xdc,0x79,0xc1,0x8f,0x29,0x44,0xf2,0xdc,0x00,0xf6,0x20,0x8d, - 0x03,0x0a,0xdd,0x66,0x1a,0x59,0x93,0x73,0x7f,0x58,0x76,0x19,0x20,0x8d, - 0x03,0x0a,0xe7,0x9c,0x7c,0xce,0x79,0xe3,0xc8,0xa4,0x73,0x66,0x20,0x8d, - 0x03,0x0a,0xe7,0xca,0xbd,0xa2,0xab,0xe5,0x7b,0xe4,0xca,0x71,0x20,0x8d, - 0x03,0x0a,0xe7,0xd1,0xe8,0x45,0x7a,0x42,0x60,0x2b,0x2c,0xde,0x20,0x8d, - 0x03,0x0a,0xe7,0xe9,0x47,0x9b,0x22,0x6c,0x6c,0x03,0xba,0x6e,0x20,0x8d, - 0x03,0x0a,0xe0,0xba,0x25,0x23,0x7f,0x25,0x5c,0x51,0xcb,0xc3,0x20,0x8d, - 0x03,0x0a,0xe1,0x21,0xbf,0x26,0x37,0xfd,0xe9,0x89,0x95,0xe2,0x20,0x8d, - 0x03,0x0a,0xe1,0x2c,0xa1,0xde,0xa2,0x37,0x7e,0x01,0xc5,0xa8,0x20,0x8d, - 0x03,0x0a,0xe1,0x57,0x53,0x20,0x2d,0x66,0x9a,0xb1,0xed,0xa0,0x20,0x8d, - 0x03,0x0a,0xe2,0x00,0xe6,0xcf,0x0c,0xe7,0xd0,0xc0,0x58,0x9c,0x20,0x8d, - 0x03,0x0a,0xe2,0x6f,0x9d,0xfd,0xce,0xa7,0x40,0x6f,0xfb,0x62,0x20,0x8d, - 0x03,0x0a,0xe3,0x1a,0xaa,0xa7,0xc7,0x07,0xf6,0x48,0x34,0x2a,0x20,0x8d, - 0x03,0x0a,0xe3,0x5b,0x4c,0x5d,0x9d,0x57,0x66,0xbc,0x26,0x1b,0x20,0x8d, - 0x03,0x0a,0xe3,0x73,0xac,0x1b,0x82,0x6b,0xa6,0x4d,0x91,0x3f,0x20,0x8d, - 0x03,0x0a,0xe3,0xdd,0x9b,0x1f,0xdd,0xf7,0x30,0x6c,0x8c,0x6a,0x20,0x8d, - 0x03,0x0a,0xe4,0x0c,0x50,0xf7,0xd1,0xab,0xc2,0xc2,0x4a,0xff,0x20,0x8d, - 0x03,0x0a,0xe4,0x64,0x0b,0xeb,0x73,0x04,0x33,0x66,0x21,0x89,0x20,0x8d, - 0x03,0x0a,0xe5,0x3a,0x9e,0x83,0x1e,0x88,0x24,0xeb,0x4f,0x8c,0x20,0x8d, - 0x03,0x0a,0xe5,0x5d,0x1a,0xcd,0xd8,0x21,0x8f,0xcc,0x86,0xb1,0x20,0x8d, - 0x03,0x0a,0xee,0xa5,0xc4,0xf5,0xeb,0x1d,0x96,0xfc,0x9e,0x76,0x20,0x8d, - 0x03,0x0a,0xe8,0x02,0xf4,0x22,0x05,0xa9,0x14,0xe2,0x26,0x2e,0x20,0x8d, - 0x03,0x0a,0xe8,0x30,0x3c,0xde,0xfe,0x4e,0x1d,0x9d,0xb4,0x99,0x20,0x8d, - 0x03,0x0a,0xe8,0xaf,0x91,0xca,0x33,0x72,0xba,0x33,0x3b,0x80,0x20,0x8d, - 0x03,0x0a,0xe9,0x07,0x44,0x29,0xf4,0x1a,0x09,0xb4,0xe2,0x25,0x20,0x8d, - 0x03,0x0a,0xe9,0x1e,0x40,0x15,0x4c,0xc0,0x38,0x5a,0xf4,0x7d,0x20,0x8d, - 0x03,0x0a,0xe9,0x71,0x75,0xe6,0x68,0x16,0xe7,0xe6,0xba,0x79,0x20,0x8d, - 0x03,0x0a,0xe9,0xc7,0xe2,0x60,0x96,0xee,0x02,0xd8,0x78,0xc1,0x20,0x8d, - 0x03,0x0a,0xea,0x70,0x5c,0x9e,0xca,0x90,0x7d,0x48,0xc5,0xfa,0x20,0x8d, - 0x03,0x0a,0xeb,0x5c,0xe8,0x18,0x53,0xef,0xbe,0x83,0x77,0xf5,0x20,0x8d, - 0x03,0x0a,0xeb,0x64,0x56,0x71,0xb0,0x86,0x72,0xf8,0xa6,0x2f,0x20,0x8d, - 0x03,0x0a,0xeb,0xa1,0x29,0xde,0x4f,0xc9,0xd6,0x64,0x90,0xbe,0x20,0x8d, - 0x03,0x0a,0xeb,0xf3,0x96,0x0f,0x93,0x2b,0x9b,0x18,0x64,0x3a,0x20,0x8d, - 0x03,0x0a,0xec,0x84,0xa6,0x5f,0x98,0xa0,0x82,0xd7,0xf1,0x0e,0x20,0x8d, - 0x03,0x0a,0xed,0x09,0xfb,0x3a,0x39,0x0b,0x7c,0x77,0x37,0x64,0x20,0x8d, - 0x03,0x0a,0xed,0xae,0x7b,0xea,0x6e,0xcb,0xdd,0x52,0xfb,0x3b,0x20,0x8d, - 0x03,0x0a,0xed,0xd5,0xbc,0x51,0xbb,0xf1,0x37,0xa2,0x6f,0x88,0x20,0x8d, - 0x03,0x0a,0xee,0x4c,0x79,0xe8,0xdf,0xa8,0xa4,0x07,0xa3,0xdd,0x20,0x8d, - 0x03,0x0a,0xf6,0x86,0x21,0xbe,0xa3,0x72,0xcb,0x95,0x0f,0x2b,0x20,0x8d, - 0x03,0x0a,0xf6,0xc2,0xa7,0x69,0x87,0x45,0xda,0xdd,0x07,0xe3,0x20,0x8d, - 0x03,0x0a,0xf7,0xce,0x9a,0x96,0xbe,0xb2,0x05,0x30,0x2d,0x9d,0x20,0x8d, - 0x03,0x0a,0xf1,0xbc,0xa7,0x71,0x4b,0x51,0x7a,0x09,0xac,0x68,0x20,0x8d, - 0x03,0x0a,0xf2,0xbb,0x98,0x90,0x97,0xb7,0x04,0x01,0xdd,0x1d,0x20,0x8d, - 0x03,0x0a,0xf2,0x8b,0xd0,0x60,0xeb,0x79,0x1b,0x8b,0x18,0x12,0x20,0x8d, - 0x03,0x0a,0xf3,0x00,0x83,0x5d,0x35,0x11,0x27,0xc7,0xa2,0x64,0x20,0x8d, - 0x03,0x0a,0xf4,0x49,0x29,0x57,0x83,0xab,0xd6,0x1e,0xa0,0xe7,0x20,0x8d, - 0x03,0x0a,0xf4,0x52,0x4b,0xf8,0xd8,0xa0,0x28,0x8d,0x8b,0xa4,0x20,0x8d, - 0x03,0x0a,0xf4,0x94,0x66,0x97,0x9b,0x7b,0xce,0x3a,0xa6,0x80,0x20,0x8d, - 0x03,0x0a,0xf4,0xa7,0x70,0x38,0x74,0xb2,0x24,0x6e,0xca,0x07,0x20,0x8d, - 0x03,0x0a,0xf5,0xe1,0x8e,0x4e,0x5e,0x0b,0xbd,0x4e,0x8c,0xcc,0x20,0x8d, - 0x03,0x0a,0xf8,0x2a,0xd5,0xec,0x70,0x79,0xa9,0xad,0xa6,0xa0,0x20,0x8d, - 0x03,0x0a,0xf9,0x4b,0xcb,0x2b,0x5e,0xf3,0x5d,0xad,0xce,0xed,0x20,0x8d, - 0x03,0x0a,0xf9,0xd0,0xf0,0xd3,0x25,0x18,0xb1,0x98,0x29,0x46,0x20,0x8d, - 0x03,0x0a,0xfc,0x92,0xc5,0xe6,0x33,0x3a,0x56,0xf2,0xe0,0x6a,0x20,0x8d, - 0x03,0x0a,0xfc,0xe9,0x3d,0xe6,0x7a,0x02,0xad,0x16,0x5b,0xd7,0x20,0x8d, - 0x03,0x0a,0xfd,0x0f,0x24,0xe5,0x3e,0x6d,0xf6,0x32,0xb6,0xf3,0x20,0x8d, - 0x03,0x0a,0xfd,0x99,0xcb,0x49,0xdb,0xb5,0x41,0x3b,0xb4,0x33,0x20,0x8d, - 0x03,0x0a,0xfe,0x14,0xcc,0xd3,0x01,0xb0,0xf4,0xf9,0xe4,0xdc,0x20,0x8d, - 0x03,0x0a,0x06,0xbe,0x1a,0x9d,0x0d,0x07,0x31,0xad,0xa6,0xee,0x20,0x8d, - 0x03,0x0a,0x07,0x77,0x59,0x8d,0x9f,0xa2,0x09,0x3e,0xd4,0x6b,0x20,0x8d, - 0x03,0x0a,0x07,0x7d,0xdf,0xea,0xe9,0xa3,0x8a,0xd9,0xe8,0x6f,0x20,0x8d, - 0x03,0x0a,0x00,0x5f,0xae,0xa9,0xa8,0x28,0xe4,0xd1,0x6a,0x35,0x20,0x8d, - 0x03,0x0a,0x01,0x0b,0x7f,0xd0,0x39,0x78,0x17,0xf1,0x2c,0x0a,0x20,0x8d, - 0x03,0x0a,0x02,0x3b,0x1d,0x0d,0x0e,0xcb,0x89,0xf8,0xc4,0x79,0x20,0x8d, - 0x03,0x0a,0x02,0x1f,0x47,0xbc,0xe8,0x9e,0xc8,0xd3,0x19,0xe9,0x20,0x8d, - 0x03,0x0a,0x02,0xcc,0xf4,0xa7,0x06,0x1e,0xcd,0x36,0xb1,0xef,0x20,0x8d, - 0x03,0x0a,0x02,0xd0,0x7a,0x03,0xf1,0x3e,0x05,0xce,0xe8,0xf1,0x20,0x8d, - 0x03,0x0a,0x03,0x36,0x6c,0x60,0xb8,0x6d,0xf3,0x6c,0x5c,0xf7,0x20,0x8d, - 0x03,0x0a,0x03,0x54,0xec,0xe4,0xa7,0x5e,0xa3,0xba,0x0b,0xd4,0x20,0x8d, - 0x03,0x0a,0x04,0xf7,0x3b,0x25,0x61,0x98,0xb4,0xb8,0x36,0x1d,0x20,0x8d, - 0x03,0x0a,0x05,0x60,0xe0,0xaf,0xfa,0x7b,0x05,0xee,0x0f,0x08,0x20,0x8d, - 0x03,0x0a,0x05,0x98,0x3c,0xe8,0xb2,0xd8,0x7a,0x7e,0xd2,0x7d,0x20,0x8d, - 0x03,0x0a,0x06,0x31,0x67,0xa3,0x1f,0xf8,0x69,0x31,0xa6,0x29,0x20,0x8d, - 0x03,0x0a,0x0e,0x91,0xb7,0xa7,0xe2,0xd7,0x05,0x57,0xc6,0x5f,0x20,0x8d, - 0x03,0x0a,0x0f,0x10,0xb2,0x07,0x17,0x15,0x3c,0xd9,0xcd,0x0e,0x20,0x8d, - 0x03,0x0a,0x0f,0x2b,0x55,0x06,0x08,0x78,0x98,0xab,0x3f,0x95,0x20,0x8d, - 0x03,0x0a,0x08,0xc6,0x58,0x5d,0xf2,0xea,0x02,0x3d,0x96,0x76,0x20,0x8d, - 0x03,0x0a,0x09,0x3a,0x13,0x09,0xee,0xe3,0x9d,0x4b,0xf6,0x18,0x20,0x8d, - 0x03,0x0a,0x09,0x96,0x0e,0x33,0xd9,0x24,0xeb,0x3a,0xfd,0x72,0x20,0x8d, - 0x03,0x0a,0x09,0xf7,0xa3,0x66,0xdb,0x6e,0x04,0xac,0xc2,0x93,0x20,0x8d, - 0x03,0x0a,0x09,0xdd,0xc5,0x38,0x6f,0x21,0xdb,0xfb,0xc7,0x77,0x20,0x8d, - 0x03,0x0a,0x0a,0x26,0x27,0x21,0xbc,0x8a,0xca,0x0e,0x5a,0x17,0x20,0x8d, - 0x03,0x0a,0x0a,0x2d,0xf9,0x79,0x25,0xf4,0x74,0xc2,0xec,0x54,0x20,0x8d, - 0x03,0x0a,0x0a,0xbf,0x87,0xf8,0x8f,0x6b,0x04,0xb5,0xc3,0xfa,0x20,0x8d, - 0x03,0x0a,0x0a,0xc4,0xa9,0xc4,0xd5,0x27,0x6a,0x49,0xa6,0x4a,0x20,0x8d, - 0x03,0x0a,0x0a,0xec,0x17,0xfc,0xc5,0x19,0x4a,0x39,0x5f,0x86,0x20,0x8d, - 0x03,0x0a,0x0b,0x6e,0xdf,0x42,0x02,0xef,0x4d,0x56,0xf5,0xcf,0x20,0x8d, - 0x03,0x0a,0x0b,0xfe,0xed,0x69,0x75,0x12,0x41,0x62,0x2e,0xb5,0x20,0x8d, - 0x03,0x0a,0x0c,0x21,0x88,0x50,0x46,0x4f,0x26,0x23,0xb7,0xdc,0x20,0x8d, - 0x03,0x0a,0x0d,0x47,0x96,0x52,0x62,0x81,0x7e,0x6c,0xe5,0xbd,0x20,0x8d, - 0x03,0x0a,0x16,0xfd,0x96,0x10,0xc9,0x52,0x1a,0x59,0xb2,0x65,0x20,0x8d, - 0x03,0x0a,0x17,0x0a,0xdf,0x68,0xcd,0x5c,0xd6,0x68,0xbe,0x75,0x20,0x8d, - 0x03,0x0a,0x10,0x00,0x45,0xf7,0x04,0x1d,0x50,0xe7,0x43,0x2a,0x20,0x8d, - 0x03,0x0a,0x10,0x21,0xde,0x00,0x2b,0x28,0x62,0xda,0x30,0x63,0x20,0x8d, - 0x03,0x0a,0x11,0x22,0xd8,0xb2,0x2a,0xee,0x5c,0xcc,0xbb,0x2d,0x20,0x8d, - 0x03,0x0a,0x11,0xe2,0x8f,0x22,0x66,0x48,0x00,0x67,0x17,0x93,0x20,0x8d, - 0x03,0x0a,0x13,0x45,0x64,0x2b,0x73,0x68,0xf4,0x44,0xb3,0xb9,0x20,0x8d, - 0x03,0x0a,0x15,0x30,0x98,0x3b,0x28,0x23,0x04,0xcb,0x02,0xeb,0x20,0x8d, - 0x03,0x0a,0x15,0xff,0x00,0x68,0xcf,0x86,0x1f,0xf7,0xac,0x7d,0x20,0x8d, - 0x03,0x0a,0x16,0x5f,0xfb,0x18,0x14,0x97,0x0d,0x54,0x3b,0xfa,0x20,0x8d, - 0x03,0x0a,0x1e,0x8a,0xde,0xf2,0x25,0xc2,0x46,0x06,0x99,0x1c,0x20,0x8d, - 0x03,0x0a,0x1e,0xa4,0xae,0x76,0x9e,0x10,0x3d,0xcc,0x12,0x07,0x20,0x8d, - 0x03,0x0a,0x1e,0xc0,0xeb,0x31,0xa6,0xaa,0xa7,0x2c,0xa0,0x04,0x20,0x8d, - 0x03,0x0a,0x1f,0x51,0x4e,0x01,0x19,0xde,0x34,0xa3,0x08,0xc9,0x20,0x8d, - 0x03,0x0a,0x1f,0xb2,0x1b,0x6a,0x57,0x6d,0xcc,0x9e,0xca,0xbb,0x20,0x8d, - 0x03,0x0a,0x18,0x7b,0x11,0xf4,0x9c,0xf4,0xfe,0xc3,0x21,0xa8,0x20,0x8d, - 0x03,0x0a,0x18,0x91,0xa3,0x51,0x6e,0x8a,0xf9,0xcc,0x27,0xbd,0x20,0x8d, - 0x03,0x0a,0x18,0xdf,0x33,0xe9,0x96,0x9e,0xe3,0x2a,0xb9,0xc6,0x20,0x8d, - 0x03,0x0a,0x19,0x63,0x6c,0x83,0xe5,0x11,0x04,0xa6,0xb5,0x92,0x20,0x8d, - 0x03,0x0a,0x1a,0x6c,0x74,0x95,0x3c,0x89,0xf6,0xec,0xef,0x09,0x20,0x8d, - 0x03,0x0a,0x1a,0x95,0xd6,0x31,0xe4,0xea,0x66,0x97,0x0d,0x5d,0x20,0x8d, - 0x03,0x0a,0x1b,0x93,0xbc,0x99,0x92,0x0e,0x69,0x16,0x40,0xcf,0x20,0x8d, - 0x03,0x0a,0x1b,0xc4,0x4e,0x17,0x71,0x14,0x06,0x3c,0x86,0xfd,0x20,0x8d, - 0x03,0x0a,0x1c,0x6c,0xed,0xd5,0xb7,0x11,0xfa,0xec,0x94,0x2e,0x20,0x8d, - 0x03,0x0a,0x1d,0x10,0xa5,0x20,0x77,0x43,0xf6,0xbc,0x12,0xed,0x20,0x8d, - 0x03,0x0a,0x1d,0x20,0x35,0xa1,0xf3,0x16,0xb4,0x8f,0x1c,0xbd,0x20,0x8d, - 0x03,0x0a,0x1d,0x30,0xfe,0x09,0xc7,0xe8,0xfe,0xd3,0xee,0x83,0x20,0x8d, - 0x03,0x0a,0x1d,0x33,0xd9,0xd9,0xdb,0xcf,0xc5,0xde,0xae,0xe9,0x20,0x8d, - 0x03,0x0a,0x1d,0x69,0xe1,0xac,0x11,0xf1,0x32,0x2f,0x5c,0x8d,0x20,0x8d, - 0x03,0x0a,0x1e,0x3d,0x98,0x4b,0x9e,0xc0,0x96,0x40,0x63,0x0f,0x20,0x8d, - 0x03,0x0a,0x1e,0x75,0x81,0xb1,0x3b,0xc4,0x22,0x26,0x72,0x3f,0x20,0x8d, - 0x03,0x0a,0x26,0x83,0xa0,0x76,0x54,0xa8,0xc1,0x6c,0xde,0x83,0x20,0x8d, - 0x03,0x0a,0x26,0xf6,0x7e,0xfd,0x3a,0x25,0x94,0xa8,0x49,0xbd,0x20,0x8d, - 0x03,0x0a,0x27,0x54,0x94,0x03,0x1f,0x7e,0x53,0xd8,0x3f,0x35,0x20,0x8d, - 0x03,0x0a,0x27,0xd0,0xa7,0x73,0x43,0xd5,0xb2,0x26,0x57,0x1c,0x20,0x8d, - 0x03,0x0a,0x20,0x3c,0x17,0x1f,0x8a,0x74,0xe1,0xdf,0x5a,0x5d,0x20,0x8d, - 0x03,0x0a,0x21,0x47,0x7f,0x18,0x5c,0x97,0x49,0x9c,0x40,0x86,0x20,0x8d, - 0x03,0x0a,0x21,0x62,0xfa,0x51,0x02,0xf5,0x14,0x4c,0x40,0x52,0x20,0x8d, - 0x03,0x0a,0x21,0xa3,0x41,0x6c,0x28,0xda,0x27,0x1a,0x78,0xd0,0x20,0x8d, - 0x03,0x0a,0x24,0x45,0xe9,0xa6,0x5a,0xa0,0xb0,0x01,0xaf,0x5b,0x20,0x8d, - 0x03,0x0a,0x25,0x09,0xa6,0xf6,0x4a,0xec,0xd5,0x33,0x74,0x35,0x20,0x8d, - 0x03,0x0a,0x26,0x55,0x1f,0xca,0x70,0xe5,0xbe,0xe3,0xa6,0x33,0x20,0x8d, - 0x03,0x0a,0x2e,0xdb,0x8c,0x24,0x20,0xf2,0x9f,0x7c,0xb4,0xea,0x20,0x8d, - 0x03,0x0a,0x28,0x21,0xfd,0xd5,0x3c,0x78,0xa5,0xfd,0xcc,0xf4,0x20,0x8d, - 0x03,0x0a,0x28,0xeb,0x35,0xa7,0x6f,0x90,0x83,0x7a,0x1f,0xfd,0x20,0x8d, - 0x03,0x0a,0x29,0x86,0xfb,0xba,0xbc,0x6e,0x6f,0x53,0x89,0xf5,0x20,0x8d, - 0x03,0x0a,0x2a,0x25,0x08,0x7a,0xb9,0x56,0xd9,0xe9,0xeb,0x5d,0x20,0x8d, - 0x03,0x0a,0x2a,0x8c,0xfd,0xc2,0xc4,0x30,0x05,0x11,0xe8,0x29,0x20,0x8d, - 0x03,0x0a,0x2b,0xb7,0x31,0x96,0xd7,0xd7,0xe6,0x05,0x42,0x1d,0x20,0x8d, - 0x03,0x0a,0x2c,0x15,0x79,0x88,0xf6,0xc3,0xd1,0x27,0xa9,0xf5,0x20,0x8d, - 0x03,0x0a,0x2c,0x28,0xda,0x1d,0x76,0xa8,0xff,0x18,0x78,0x7d,0x20,0x8d, - 0x03,0x0a,0x2c,0x6d,0x3e,0xb2,0x42,0x7e,0x0e,0x8a,0x59,0xe4,0x20,0x8d, - 0x03,0x0a,0x2c,0xc1,0xc3,0x15,0x28,0xa5,0x7c,0x5d,0x2c,0x9a,0x20,0x8d, - 0x03,0x0a,0x2d,0x1d,0x8d,0x21,0xf4,0x84,0x61,0x62,0x74,0x45,0x20,0x8d, - 0x03,0x0a,0x2e,0x7c,0xd9,0x21,0x3e,0x4a,0x31,0x4b,0x2e,0x42,0x20,0x8d, - 0x03,0x0a,0x36,0xea,0xb6,0x80,0x00,0x71,0xbb,0x23,0x51,0x1d,0x20,0x8d, - 0x03,0x0a,0x37,0x38,0x8f,0x26,0xd2,0xa4,0xd5,0x66,0x49,0xf9,0x20,0x8d, - 0x03,0x0a,0x37,0x7b,0x3f,0x74,0x7d,0x12,0x92,0x8b,0x89,0xb6,0x20,0x8d, - 0x03,0x0a,0x30,0x12,0x3f,0x13,0x11,0x5e,0xa1,0x65,0x15,0x86,0x20,0x8d, - 0x03,0x0a,0x30,0x57,0x42,0x6c,0xf1,0xee,0xdf,0xc3,0x46,0xff,0x20,0x8d, - 0x03,0x0a,0x30,0x5f,0x17,0x76,0x79,0x1d,0x11,0x42,0x97,0x95,0x20,0x8d, - 0x03,0x0a,0x30,0xb8,0xbd,0xce,0x0b,0xde,0xa0,0x72,0x99,0x88,0x20,0x8d, - 0x03,0x0a,0x30,0x9a,0xb7,0x46,0xb3,0x7e,0x05,0x40,0x24,0x5e,0x20,0x8d, - 0x03,0x0a,0x30,0xe4,0x80,0xe9,0xaa,0xd1,0x08,0xe4,0x0c,0xc2,0x20,0x8d, - 0x03,0x0a,0x31,0x3a,0x66,0x7c,0x5e,0xb7,0xf0,0x03,0xbf,0x3f,0x20,0x8d, - 0x03,0x0a,0x31,0x0c,0x29,0x90,0x84,0x7f,0x05,0x62,0xcd,0x7d,0x20,0x8d, - 0x03,0x0a,0x31,0x5d,0x88,0x82,0x83,0x35,0x7b,0x04,0x8d,0x54,0x20,0x8d, - 0x03,0x0a,0x31,0x9e,0x1a,0x61,0xec,0xb9,0x91,0xaf,0x2c,0x5e,0x20,0x8d, - 0x03,0x0a,0x31,0xe0,0x8a,0xe0,0x9f,0x11,0x44,0xa4,0x49,0xb3,0x20,0x8d, - 0x03,0x0a,0x32,0x22,0x05,0x5d,0xcc,0x69,0x3a,0x50,0xe3,0xdc,0x20,0x8d, - 0x03,0x0a,0x32,0xf3,0xd3,0x15,0x5b,0xdc,0xe9,0x43,0x75,0xa4,0x20,0x8d, - 0x03,0x0a,0x33,0xd6,0x09,0xdd,0xd8,0x37,0x5b,0x75,0xf6,0x29,0x20,0x8d, - 0x03,0x0a,0x34,0x50,0xf5,0xf6,0xe9,0xb6,0x34,0x31,0x47,0xc2,0x20,0x8d, - 0x03,0x0a,0x34,0xce,0x7c,0xad,0x90,0x12,0x35,0xa6,0xde,0x34,0x20,0x8d, - 0x03,0x0a,0x34,0xdd,0xa1,0xfb,0x92,0xb3,0xa4,0x56,0x2b,0xc2,0x20,0x8d, - 0x03,0x0a,0x35,0x00,0x24,0x34,0x98,0xee,0x98,0x61,0x05,0xfa,0x20,0x8d, - 0x03,0x0a,0x35,0x95,0x33,0x45,0x93,0xb2,0xbc,0xda,0xf6,0x42,0x20,0x8d, - 0x03,0x0a,0x35,0x9d,0x76,0xb9,0x43,0x15,0x85,0xf3,0xe3,0x8f,0x20,0x8d, - 0x03,0x0a,0x3e,0xf7,0xb2,0xf2,0x0d,0xb1,0x3e,0xc8,0xe1,0x8d,0x20,0x8d, - 0x03,0x0a,0x3f,0x81,0xbd,0x37,0x81,0x58,0x6d,0x6c,0x37,0x83,0x20,0x8d, - 0x03,0x0a,0x38,0x0b,0x69,0xc4,0x2e,0x74,0xb2,0xe2,0x30,0x2c,0x20,0x8d, - 0x03,0x0a,0x38,0x6c,0x73,0x48,0x3b,0x21,0x10,0xd6,0xc7,0xd3,0x20,0x8d, - 0x03,0x0a,0x38,0xab,0xe2,0xba,0xe7,0xeb,0x15,0xf2,0x9c,0x3d,0x20,0x8d, - 0x03,0x0a,0x38,0xfc,0x75,0x4c,0x4b,0xf5,0x80,0xcc,0xaf,0x2c,0x20,0x8d, - 0x03,0x0a,0x38,0xc1,0xe6,0x48,0x1c,0xaf,0x23,0x3f,0xfc,0xd7,0x20,0x8d, - 0x03,0x0a,0x38,0xcc,0xdb,0xaa,0x90,0x90,0xfd,0x64,0xda,0xd7,0x20,0x8d, - 0x03,0x0a,0x39,0x8f,0xb0,0x65,0xbb,0x21,0x24,0x31,0xd4,0x46,0x20,0x8d, - 0x03,0x0a,0x39,0xf1,0x7a,0x78,0x36,0x52,0x48,0x52,0x25,0xd9,0x20,0x8d, - 0x03,0x0a,0x3a,0x32,0xdf,0x45,0x8e,0x2c,0x8d,0xba,0x3d,0x8d,0x20,0x8d, - 0x03,0x0a,0x3a,0x61,0x7b,0xcb,0x1a,0x74,0x88,0xc2,0xd4,0x95,0x20,0x8d, - 0x03,0x0a,0x3a,0x82,0xff,0xb0,0x26,0xb7,0x94,0xb5,0xcb,0x92,0x20,0x8d, - 0x03,0x0a,0x3a,0xdc,0x9a,0x59,0x16,0x0a,0x9c,0x9e,0x28,0x79,0x20,0x8d, - 0x03,0x0a,0x3a,0xf3,0x79,0x26,0x3f,0x70,0x77,0x0c,0xe6,0x10,0x20,0x8d, - 0x03,0x0a,0x3b,0x51,0x4c,0xbd,0x64,0xc9,0x03,0x83,0xd7,0xe0,0x20,0x8d, - 0x03,0x0a,0x3b,0x9a,0x32,0x59,0x49,0xe4,0xb9,0x11,0x8a,0xc5,0x20,0x8d, - 0x03,0x0a,0x3c,0x17,0xd6,0xd7,0xd5,0x38,0x88,0x81,0xec,0x2d,0x20,0x8d, - 0x03,0x0a,0x3c,0x9e,0x97,0x7d,0x90,0x8c,0x49,0xd3,0x62,0xf1,0x20,0x8d, - 0x03,0x0a,0x3d,0x3d,0xc9,0x69,0x83,0x8e,0xef,0xfc,0x5d,0x40,0x20,0x8d, - 0x03,0x0a,0x3d,0x6d,0x58,0x6a,0x56,0x54,0x2d,0xb8,0x57,0x0e,0x20,0x8d, - 0x03,0x0a,0x3d,0x9d,0xa0,0xa3,0x0d,0x1c,0x63,0x57,0xaf,0xc5,0x20,0x8d, - 0x03,0x0a,0x3e,0x6e,0x9d,0x8e,0x67,0xde,0x35,0x79,0xf3,0xae,0x20,0x8d, - 0x03,0x0a,0x46,0xe8,0x5b,0xd2,0xdb,0x9f,0xc5,0x72,0x8d,0xf0,0x20,0x8d, - 0x03,0x0a,0x40,0x36,0xdd,0xc3,0xb4,0xe7,0x4d,0x57,0xdf,0xe0,0x20,0x8d, - 0x03,0x0a,0x40,0x8a,0x69,0x6c,0xa2,0x98,0x94,0x3e,0x60,0x8e,0x20,0x8d, - 0x03,0x0a,0x40,0x9f,0x9f,0x4c,0xf0,0xa8,0xd2,0x2b,0x2e,0xa1,0x20,0x8d, - 0x03,0x0a,0x41,0x77,0xac,0xbb,0xb4,0xe3,0x0e,0x3a,0x34,0xa3,0x20,0x8d, - 0x03,0x0a,0x41,0xb8,0xb3,0x52,0x0b,0xf5,0x6e,0xa0,0xb1,0x91,0x20,0x8d, - 0x03,0x0a,0x41,0xce,0x28,0xfc,0xa7,0x16,0x60,0x30,0x0b,0x98,0x20,0x8d, - 0x03,0x0a,0x42,0x59,0xa9,0xe2,0xee,0x0f,0xea,0xaa,0x83,0x39,0x20,0x8d, - 0x03,0x0a,0x43,0xf6,0xfa,0x52,0x06,0x3d,0x18,0x5c,0xf6,0xd6,0x20,0x8d, - 0x03,0x0a,0x44,0x36,0xa2,0x4f,0xfa,0x2e,0xf1,0xa2,0xc5,0xe6,0x20,0x8d, - 0x03,0x0a,0x44,0x00,0x69,0xf4,0x4e,0xe0,0xe7,0xf3,0xf8,0xe5,0x20,0x8d, - 0x03,0x0a,0x45,0x0d,0x6e,0x69,0x07,0xf1,0xdf,0x18,0x47,0x5e,0x20,0x8d, - 0x03,0x0a,0x45,0x4b,0xff,0xf2,0xbc,0x9f,0xd5,0xed,0xa3,0xc3,0x20,0x8d, - 0x03,0x0a,0x45,0x4a,0x01,0x0c,0xbf,0x12,0x0d,0xac,0xeb,0x1a,0x20,0x8d, - 0x03,0x0a,0x45,0x65,0x71,0xd9,0x54,0xeb,0x8d,0xac,0xa7,0x8b,0x20,0x8d, - 0x03,0x0a,0x45,0xec,0x68,0x9c,0x0a,0x5d,0x69,0xc3,0x79,0xdf,0x20,0x8d, - 0x03,0x0a,0x46,0x7b,0xe6,0x39,0xde,0x62,0x9f,0xb3,0x7e,0xee,0x20,0x8d, - 0x03,0x0a,0x4e,0x84,0xfe,0xb2,0x96,0xea,0x76,0xba,0x30,0x57,0x20,0x8d, - 0x03,0x0a,0x4e,0x97,0x15,0x46,0xd4,0x32,0xc7,0x62,0x5a,0xd2,0x20,0x8d, - 0x03,0x0a,0x4e,0xa1,0x36,0x28,0x7a,0x18,0x02,0xb9,0x4b,0x3c,0x20,0x8d, - 0x03,0x0a,0x4f,0x49,0xac,0x50,0x0d,0xef,0xeb,0xa3,0xf4,0x8b,0x20,0x8d, - 0x03,0x0a,0x4f,0x52,0x58,0x8e,0x67,0x84,0xfa,0x6d,0x76,0xf9,0x20,0x8d, - 0x03,0x0a,0x4f,0x56,0xad,0x52,0xba,0x0c,0x9e,0x58,0x5c,0xaa,0x20,0x8d, - 0x03,0x0a,0x48,0x1b,0x5a,0xe6,0x4c,0xc8,0xa4,0x9d,0x95,0x0b,0x20,0x8d, - 0x03,0x0a,0x49,0x1a,0xdd,0x4d,0x98,0x5e,0xef,0x70,0x45,0x90,0x20,0x8d, - 0x03,0x0a,0x49,0x5c,0x4e,0x97,0x52,0x16,0x5c,0x92,0xbf,0x7a,0x20,0x8d, - 0x03,0x0a,0x49,0x84,0x64,0x79,0x5a,0x7d,0xdc,0xe4,0x76,0x1b,0x20,0x8d, - 0x03,0x0a,0x49,0xc0,0xd0,0x6b,0x92,0xd8,0xf2,0xa4,0x4f,0x2f,0x20,0x8d, - 0x03,0x0a,0x4a,0x26,0x6a,0x2c,0x3a,0xe3,0x2a,0x58,0x44,0x66,0x20,0x8d, - 0x03,0x0a,0x4a,0x69,0x5b,0x05,0x25,0xca,0xd2,0xc6,0xfe,0x7b,0x20,0x8d, - 0x03,0x0a,0x4a,0xc4,0x57,0x30,0xd1,0xed,0xca,0x4b,0x81,0x05,0x20,0x8d, - 0x03,0x0a,0x4a,0xc8,0x79,0x7b,0x01,0x0e,0xbd,0x05,0xb5,0xa0,0x20,0x8d, - 0x03,0x0a,0x4a,0xd3,0x9c,0xf2,0x6c,0x0c,0x23,0x78,0x6e,0x1d,0x20,0x8d, - 0x03,0x0a,0x4b,0x85,0xc7,0x40,0x44,0x20,0xd4,0x6f,0xfe,0xa5,0x20,0x8d, - 0x03,0x0a,0x4c,0x7b,0x8f,0x35,0x34,0x08,0x83,0x5f,0x1b,0x7f,0x20,0x8d, - 0x03,0x0a,0x4c,0x5c,0x07,0x4b,0xcb,0x07,0x2a,0x82,0x1d,0xdc,0x20,0x8d, - 0x03,0x0a,0x4c,0x98,0xf3,0x99,0x40,0xc7,0xd0,0x83,0x85,0x51,0x20,0x8d, - 0x03,0x0a,0x4c,0xd5,0x26,0xb9,0x54,0x90,0x72,0xc9,0x7e,0xcb,0x20,0x8d, - 0x03,0x0a,0x4d,0x3a,0x3a,0x3b,0x71,0xf3,0xfc,0x34,0x65,0xa2,0x20,0x8d, - 0x03,0x0a,0x4d,0xbd,0x9c,0x32,0xe2,0x69,0x02,0x03,0xd2,0x89,0x20,0x8d, - 0x03,0x0a,0x4d,0xc0,0xba,0x9c,0xbf,0xb7,0xec,0x4a,0xc3,0x36,0x20,0x8d, - 0x03,0x0a,0x4e,0x32,0x72,0x6d,0x06,0xe7,0x10,0x25,0x62,0x41,0x20,0x8d, - 0x03,0x0a,0x4e,0x49,0xea,0x29,0xbc,0x40,0xe2,0x7e,0x70,0x8e,0x20,0x8d, - 0x03,0x0a,0x57,0x0c,0xb7,0x4d,0x77,0x6b,0x27,0x30,0xf8,0x53,0x20,0x8d, - 0x03,0x0a,0x57,0xe9,0x8d,0xa2,0xcc,0xa9,0xa9,0x9c,0x18,0x7a,0x20,0x8d, - 0x03,0x0a,0x52,0xf5,0xb7,0x14,0x06,0xdd,0x14,0x1f,0x1e,0xeb,0x20,0x8d, - 0x03,0x0a,0x53,0x95,0x3d,0x42,0x3e,0x1f,0x1e,0xcc,0x07,0x43,0x20,0x8d, - 0x03,0x0a,0x53,0xc0,0xba,0x6c,0xfd,0xc0,0xd4,0xe0,0x22,0xb2,0x20,0x8d, - 0x03,0x0a,0x54,0x46,0xf0,0x8e,0xb3,0x85,0xba,0x2e,0xac,0x84,0x20,0x8d, - 0x03,0x0a,0x54,0x51,0x6f,0x2b,0x29,0xc8,0x23,0x93,0x07,0x66,0x20,0x8d, - 0x03,0x0a,0x54,0x5f,0xa9,0x9c,0x4c,0xb4,0x5f,0x27,0x50,0x9e,0x20,0x8d, - 0x03,0x0a,0x55,0x71,0x51,0xd9,0x36,0x98,0x09,0xd6,0x3b,0xff,0x20,0x8d, - 0x03,0x0a,0x56,0x23,0x78,0xa3,0xb1,0x0c,0x7c,0x87,0xd2,0x32,0x20,0x8d, - 0x03,0x0a,0x56,0x76,0xeb,0x9b,0xff,0xe7,0x47,0x79,0xfb,0x50,0x20,0x8d, - 0x03,0x0a,0x5e,0xed,0xd2,0x89,0x48,0xd5,0x83,0x17,0x6a,0x01,0x20,0x8d, - 0x03,0x0a,0x5f,0x38,0x14,0x4a,0x97,0x39,0xff,0x12,0x07,0xb0,0x20,0x8d, - 0x03,0x0a,0x5f,0x7d,0xd3,0x77,0x5b,0x23,0x12,0x40,0xd2,0x49,0x20,0x8d, - 0x03,0x0a,0x5f,0xad,0xd5,0x0c,0x88,0x35,0xa4,0x66,0x97,0xb3,0x20,0x8d, - 0x03,0x0a,0x5f,0xc1,0xc2,0x32,0x38,0x2d,0xd4,0x93,0x31,0x81,0x20,0x8d, - 0x03,0x0a,0x5f,0xe4,0xb7,0x48,0x49,0x84,0x02,0x82,0x8a,0x56,0x20,0x8d, - 0x03,0x0a,0x58,0x00,0x54,0xc2,0xb3,0x71,0xbe,0x34,0x95,0x7a,0x20,0x8d, - 0x03,0x0a,0x58,0x0f,0xef,0xf9,0x57,0x09,0x82,0x6b,0x6e,0x9a,0x20,0x8d, - 0x03,0x0a,0x58,0x61,0xa0,0x7d,0xed,0x7b,0x2a,0x8b,0x6a,0x0e,0x20,0x8d, - 0x03,0x0a,0x58,0xb9,0x66,0xbe,0x0b,0xd7,0xeb,0x86,0x23,0x7d,0x20,0x8d, - 0x03,0x0a,0x58,0xdc,0x52,0x84,0xaf,0x56,0xd3,0xe1,0x7f,0x1f,0x20,0x8d, - 0x03,0x0a,0x59,0x0e,0xf6,0x19,0x6a,0x45,0x5c,0x18,0x6a,0x0e,0x20,0x8d, - 0x03,0x0a,0x59,0x89,0x67,0xa7,0x3f,0x41,0x3e,0x30,0x42,0x11,0x20,0x8d, - 0x03,0x0a,0x59,0x95,0x50,0xd6,0x2e,0xf7,0xd2,0xe6,0x3a,0x56,0x20,0x8d, - 0x03,0x0a,0x5a,0x2d,0xdc,0xf1,0xa6,0x40,0xbc,0x1f,0xd5,0xb5,0x20,0x8d, - 0x03,0x0a,0x5a,0x65,0xf3,0x5a,0x2c,0x66,0x41,0xe8,0x78,0xc0,0x20,0x8d, - 0x03,0x0a,0x5b,0x2a,0x0b,0xec,0x9e,0x05,0x81,0x7a,0x9e,0x08,0x20,0x8d, - 0x03,0x0a,0x5c,0x73,0xff,0x8e,0xc5,0xfe,0x21,0xc1,0x19,0xb3,0x20,0x8d, - 0x03,0x0a,0x5d,0x41,0xde,0x3d,0xa1,0x86,0x9b,0x26,0x27,0x11,0x20,0x8d, - 0x03,0x0a,0x5d,0xc5,0xaa,0x3c,0xf7,0xc6,0x2e,0x55,0x9d,0xa5,0x20,0x8d, - 0x03,0x0a,0x5e,0x13,0x80,0x8e,0x3c,0x3b,0x13,0xb0,0xc0,0x01,0x20,0x8d, - 0x03,0x0a,0x5e,0x75,0x95,0xb5,0x98,0xc3,0x6d,0x33,0x58,0xba,0x20,0x8d, - 0x03,0x0a,0x67,0x8e,0x26,0xbd,0x0a,0x43,0x30,0x7d,0xff,0x0f,0x20,0x8d, - 0x03,0x0a,0x60,0xfd,0xbe,0xb9,0x89,0x6c,0x4c,0x72,0x10,0x7b,0x20,0x8d, - 0x03,0x0a,0x60,0xc3,0xb7,0x51,0xf6,0x2f,0x0b,0xa8,0x61,0x21,0x20,0x8d, - 0x03,0x0a,0x61,0x3c,0x3e,0x12,0x57,0xfb,0x8e,0x36,0xdd,0xa4,0x20,0x8d, - 0x03,0x0a,0x61,0x04,0x55,0x21,0x5d,0x12,0x39,0xfb,0x09,0x49,0x20,0x8d, - 0x03,0x0a,0x61,0x63,0x52,0x55,0xbf,0xb7,0xa3,0x69,0x3f,0x91,0x20,0x8d, - 0x03,0x0a,0x62,0x19,0x4a,0x4d,0x64,0xb7,0x65,0x19,0x8e,0x8a,0x20,0x8d, - 0x03,0x0a,0x63,0x71,0x25,0x6d,0x19,0xbd,0x62,0x0d,0x9e,0x95,0x20,0x8d, - 0x03,0x0a,0x64,0x29,0xe3,0x42,0x71,0x3b,0x3d,0x7c,0xda,0xc7,0x20,0x8d, - 0x03,0x0a,0x65,0xa8,0x2f,0x55,0xcc,0xe3,0x4c,0x84,0xcc,0x3b,0x20,0x8d, - 0x03,0x0a,0x65,0xc7,0x38,0xa4,0xe4,0xd6,0x0b,0x2b,0xed,0xe6,0x20,0x8d, - 0x03,0x0a,0x6f,0x10,0x12,0x4f,0x8f,0x44,0x85,0x5d,0x69,0xa9,0x20,0x8d, - 0x03,0x0a,0x6f,0x87,0xcf,0x54,0x39,0xbf,0x36,0x12,0x55,0x61,0x20,0x8d, - 0x03,0x0a,0x6f,0xa7,0xe5,0x14,0xd9,0x5d,0x5d,0x9b,0x9c,0xac,0x20,0x8d, - 0x03,0x0a,0x6f,0xe3,0x17,0x08,0xf6,0x24,0x4b,0xa8,0x5f,0x24,0x20,0x8d, - 0x03,0x0a,0x68,0xa4,0x34,0x41,0x8d,0xb9,0xda,0xd4,0x86,0x59,0x20,0x8d, - 0x03,0x0a,0x6a,0x27,0x7b,0x6d,0x0b,0x29,0x5a,0x67,0xd1,0x95,0x20,0x8d, - 0x03,0x0a,0x6a,0x57,0x2a,0xd0,0x28,0x58,0xc8,0x75,0xd2,0xd1,0x20,0x8d, - 0x03,0x0a,0x6a,0x64,0xb2,0xc9,0x15,0xc6,0x0e,0x8b,0x86,0x4f,0x20,0x8d, - 0x03,0x0a,0x6a,0x8b,0xd2,0x78,0x3f,0x7a,0xf8,0x92,0x8f,0x80,0x20,0x8d, - 0x03,0x0a,0x6a,0x9e,0xf9,0x07,0x73,0xd8,0xe8,0x24,0x93,0xcc,0x20,0x8d, - 0x03,0x0a,0x6a,0xcb,0x6c,0x41,0x52,0x61,0x20,0x4e,0x77,0x39,0x20,0x8d, - 0x03,0x0a,0x6a,0xf0,0x96,0x3c,0x4c,0x78,0x33,0xd0,0xf0,0x00,0x20,0x8d, - 0x03,0x0a,0x6b,0x59,0x5f,0xe7,0xdd,0x57,0xba,0xc1,0x12,0x51,0x20,0x8d, - 0x03,0x0a,0x6c,0x62,0x5b,0x0d,0x91,0x66,0xd0,0xca,0x10,0x2d,0x20,0x8d, - 0x03,0x0a,0x6c,0x62,0xc5,0x19,0x94,0x5b,0xcd,0x20,0xd9,0x73,0x20,0x8d, - 0x03,0x0a,0x6d,0xb8,0x7f,0xac,0x82,0x55,0x27,0xf2,0x01,0xf5,0x20,0x8d, - 0x03,0x0a,0x6d,0x95,0x8d,0xd8,0x7b,0x41,0xdc,0x81,0xd4,0x3d,0x20,0x8d, - 0x03,0x0a,0x6e,0x38,0xa5,0x11,0x8c,0x64,0x2b,0xc5,0xbe,0x6c,0x20,0x8d, - 0x03,0x0a,0x76,0xbb,0x65,0x0a,0xdf,0x23,0xa2,0x6d,0x4d,0xc8,0x20,0x8d, - 0x03,0x0a,0x76,0x8d,0x46,0x54,0x2a,0xb7,0x9e,0xce,0x74,0x45,0x20,0x8d, - 0x03,0x0a,0x77,0x30,0x99,0x1c,0x76,0x58,0x64,0x7c,0x2e,0x16,0x20,0x8d, - 0x03,0x0a,0x71,0x6f,0xc8,0x1a,0xde,0x5b,0xde,0xda,0xcc,0xd5,0x20,0x8d, - 0x03,0x0a,0x72,0x89,0x34,0x3d,0x7c,0x33,0x47,0x01,0x02,0x92,0x20,0x8d, - 0x03,0x0a,0x74,0x3b,0x0e,0x42,0x30,0x42,0x63,0xa5,0x3e,0x8d,0x20,0x8d, - 0x03,0x0a,0x74,0x2d,0xb6,0x15,0xc8,0x70,0x60,0x25,0x2e,0xe7,0x20,0x8d, - 0x03,0x0a,0x74,0x65,0x8d,0x57,0xdb,0x20,0xa2,0xc1,0xa7,0xbd,0x20,0x8d, - 0x03,0x0a,0x74,0xf9,0x3c,0xb3,0x2d,0xc2,0x18,0xc5,0xcb,0x2a,0x20,0x8d, - 0x03,0x0a,0x75,0x95,0xe1,0x69,0x25,0x99,0xec,0xac,0x00,0xe4,0x20,0x8d, - 0x03,0x0a,0x76,0x3f,0x29,0x6c,0xec,0xd3,0x95,0x7e,0x4e,0x8d,0x20,0x8d, - 0x03,0x0a,0x7e,0x9e,0x2f,0x58,0x20,0x23,0xea,0x34,0x78,0x44,0x20,0x8d, - 0x03,0x0a,0x7e,0xaf,0xae,0x18,0x67,0x04,0x98,0x61,0x2f,0xa9,0x20,0x8d, - 0x03,0x0a,0x7f,0x84,0xea,0x51,0x31,0xd3,0x46,0x75,0xae,0xbb,0x20,0x8d, - 0x03,0x0a,0x78,0x3e,0x3b,0x74,0x2b,0x6f,0x57,0x06,0x53,0xbb,0x20,0x8d, - 0x03,0x0a,0x78,0x24,0xc1,0x1e,0x6e,0x73,0x93,0xa5,0x08,0xe3,0x20,0x8d, - 0x03,0x0a,0x78,0xc0,0xf5,0x28,0xea,0xf3,0xc2,0x2c,0x6a,0x69,0x20,0x8d, - 0x03,0x0a,0x79,0x0f,0xd0,0x25,0xd4,0xa5,0xbc,0xcb,0x72,0x51,0x20,0x8d, - 0x03,0x0a,0x7a,0xa9,0x41,0x75,0xf6,0x5f,0x6f,0x83,0x58,0xf1,0x20,0x8d, - 0x03,0x0a,0x7c,0x39,0x64,0xaf,0xf5,0x37,0xe7,0x22,0xe0,0x42,0x20,0x8d, - 0x03,0x0a,0x7c,0xc3,0x68,0x1e,0x92,0x7c,0xbb,0x04,0x12,0x0b,0x20,0x8d, - 0x03,0x0a,0x7c,0xec,0xf0,0xdb,0x09,0xea,0xdb,0x82,0x5b,0x45,0x20,0x8d, - 0x03,0x0a,0x7d,0x3f,0x6d,0xa4,0xb8,0x8e,0x5f,0xf9,0x5e,0x48,0x20,0x8d, - 0x03,0x0a,0x7d,0xb0,0xb0,0xe2,0xa5,0xa0,0xbd,0xa3,0x9e,0xb7,0x20,0x8d, - 0x03,0x0a,0x86,0x8a,0x76,0xb7,0x13,0xe8,0x74,0x0c,0x54,0x44,0x20,0x8d, - 0x03,0x0a,0x86,0xd1,0xb0,0x3e,0x88,0x73,0x42,0x0c,0xb0,0xa4,0x20,0x8d, - 0x03,0x0a,0x80,0xfc,0x51,0x3e,0x9b,0x7d,0x42,0x5d,0x63,0x77,0x20,0x8d, - 0x03,0x0a,0x81,0x49,0x6a,0xef,0x1f,0x06,0xdf,0xc4,0x6c,0x23,0x20,0x8d, - 0x03,0x0a,0x81,0xf1,0x31,0xce,0x65,0x59,0xc2,0x2e,0x46,0x47,0x20,0x8d, - 0x03,0x0a,0x82,0x9b,0xbe,0xc4,0x3b,0xbe,0x8d,0x70,0xda,0x1c,0x20,0x8d, - 0x03,0x0a,0x82,0xea,0xb2,0x5e,0x5f,0x7d,0x80,0x2d,0x17,0x81,0x20,0x8d, - 0x03,0x0a,0x83,0x8c,0x28,0x22,0x33,0xa4,0xc1,0xe8,0xae,0xe6,0x20,0x8d, - 0x03,0x0a,0x84,0x73,0x02,0xdd,0x47,0x8b,0x29,0xda,0xf6,0x2e,0x20,0x8d, - 0x03,0x0a,0x84,0xb0,0x90,0x4a,0x1c,0xf0,0x75,0x2c,0x23,0x12,0x20,0x8d, - 0x03,0x0a,0x85,0x29,0xc0,0xeb,0x29,0x0b,0x63,0xaa,0x13,0x98,0x20,0x8d, - 0x03,0x0a,0x85,0x30,0x22,0xa7,0x56,0x23,0x73,0xe0,0x97,0x03,0x20,0x8d, - 0x03,0x0a,0x85,0x47,0x8d,0x89,0x8e,0x13,0x57,0x5e,0xd7,0xe2,0x20,0x8d, - 0x03,0x0a,0x85,0x6c,0x77,0xc3,0x06,0x03,0x75,0x75,0x63,0xa7,0x20,0x8d, - 0x03,0x0a,0x86,0x29,0x3b,0x0b,0x5e,0xa2,0xd7,0x44,0x80,0xa1,0x20,0x8d, - 0x03,0x0a,0x8f,0x3b,0x03,0x68,0x7e,0x45,0x8a,0x33,0xc2,0xcb,0x20,0x8d, - 0x03,0x0a,0x8f,0x2f,0x41,0xc7,0xd4,0xe4,0x7a,0xdc,0x18,0x1c,0x20,0x8d, - 0x03,0x0a,0x8f,0x80,0xf0,0x76,0x52,0xa2,0x6e,0x1b,0x0f,0x7c,0x20,0x8d, - 0x03,0x0a,0x8f,0xb3,0xa3,0x0a,0x54,0xdf,0xd5,0xb3,0x00,0x07,0x20,0x8d, - 0x03,0x0a,0x88,0x62,0x93,0x14,0x42,0x07,0xab,0xd0,0xff,0x0e,0x20,0x8d, - 0x03,0x0a,0x88,0x90,0x5b,0xa0,0x20,0xb4,0x27,0xe8,0xdf,0x39,0x20,0x8d, - 0x03,0x0a,0x88,0xdd,0xbb,0x8a,0x6a,0xde,0x55,0x94,0xd5,0x6d,0x20,0x8d, - 0x03,0x0a,0x88,0xea,0xb2,0x3f,0x1e,0x31,0xcc,0xf0,0x3f,0x2e,0x20,0x8d, - 0x03,0x0a,0x89,0x05,0x2d,0x83,0x5f,0x11,0xeb,0xa5,0x9b,0xdd,0x20,0x8d, - 0x03,0x0a,0x89,0x58,0x14,0x63,0xb5,0xcc,0xea,0xdf,0x1f,0x0d,0x20,0x8d, - 0x03,0x0a,0x8a,0xd1,0xd5,0x85,0x24,0xe2,0xbf,0xf4,0x37,0x36,0x20,0x8d, - 0x03,0x0a,0x8b,0xa1,0x66,0xb0,0x8f,0x12,0x79,0xdd,0xd4,0xa7,0x20,0x8d, - 0x03,0x0a,0x8b,0xc2,0xdb,0xf7,0x90,0x6a,0x11,0x58,0xb0,0xfb,0x20,0x8d, - 0x03,0x0a,0x8c,0xab,0x57,0x1a,0x03,0x5a,0x12,0xff,0xfc,0xf5,0x20,0x8d, - 0x03,0x0a,0x8d,0x99,0xd1,0xf0,0xe6,0xd9,0xc5,0xff,0xa8,0x73,0x20,0x8d, - 0x03,0x0a,0x96,0xf0,0x45,0xaa,0xa2,0xe9,0x7b,0x72,0x62,0x56,0x20,0x8d, - 0x03,0x0a,0x97,0xa3,0x7e,0xe8,0xe8,0x9b,0x1e,0xfe,0x2c,0xc4,0x20,0x8d, - 0x03,0x0a,0x90,0x3c,0xcd,0xc6,0xb8,0x12,0x1e,0x62,0x31,0x58,0x20,0x8d, - 0x03,0x0a,0x90,0x2a,0x40,0x90,0x92,0x62,0x91,0x56,0x14,0x2e,0x20,0x8d, - 0x03,0x0a,0x90,0x70,0x98,0xf5,0xaf,0x56,0x98,0xb6,0x16,0xdf,0x20,0x8d, - 0x03,0x0a,0x91,0x23,0x64,0xf3,0x49,0x61,0x3b,0x73,0x9d,0x96,0x20,0x8d, - 0x03,0x0a,0x91,0xb9,0x56,0x50,0x35,0xd8,0xd3,0x1c,0xd6,0x87,0x20,0x8d, - 0x03,0x0a,0x91,0xe4,0x65,0x49,0x74,0xcf,0x92,0xa3,0x3f,0xc6,0x20,0x8d, - 0x03,0x0a,0x92,0x71,0x96,0x5a,0xd4,0xf0,0xd0,0x84,0x4f,0x71,0x20,0x8d, - 0x03,0x0a,0x92,0xb6,0x46,0xee,0x24,0xa0,0xcd,0xb9,0x0c,0xdd,0x20,0x8d, - 0x03,0x0a,0x92,0x9c,0x82,0xbf,0x8e,0x4f,0xd7,0xc7,0x4a,0x9d,0x20,0x8d, - 0x03,0x0a,0x92,0xc9,0xa1,0x01,0xeb,0x52,0xdb,0xbd,0x93,0xf8,0x20,0x8d, - 0x03,0x0a,0x93,0x06,0x3f,0xc3,0xe6,0x73,0x40,0x91,0xb1,0x30,0x20,0x8d, - 0x03,0x0a,0x93,0xd8,0x7a,0x5d,0x21,0xd0,0x87,0xf5,0x92,0x8d,0x20,0x8d, - 0x03,0x0a,0x94,0x54,0x6c,0x57,0xa4,0x1b,0x74,0xf0,0x7d,0x0b,0x20,0x8d, - 0x03,0x0a,0x94,0x96,0xd4,0xa4,0xed,0x65,0x96,0xbc,0x4a,0xbc,0x20,0x8d, - 0x03,0x0a,0x95,0x3d,0xec,0x1a,0x20,0x97,0xa2,0xa1,0xcd,0xab,0x20,0x8d, - 0x03,0x0a,0x95,0x1a,0x3a,0xb0,0x29,0x8c,0xcc,0x32,0x80,0xf7,0x20,0x8d, - 0x03,0x0a,0x95,0x47,0xee,0xab,0xa9,0x78,0x17,0xa7,0xed,0x73,0x20,0x8d, - 0x03,0x0a,0x95,0x68,0x0e,0x9d,0x10,0x5d,0x2d,0xf7,0x6a,0x56,0x20,0x8d, - 0x03,0x0a,0x95,0xe0,0x9a,0x05,0x94,0x67,0x22,0xc2,0x99,0xf4,0x20,0x8d, - 0x03,0x0a,0x9e,0xb9,0xda,0xa3,0xfc,0xd4,0xd1,0xb9,0xb5,0x40,0x20,0x8d, - 0x03,0x0a,0x9f,0x0a,0x17,0x56,0xa6,0xcb,0xda,0x86,0x0f,0x4f,0x20,0x8d, - 0x03,0x0a,0x9f,0x17,0xcb,0x57,0x64,0x8a,0x8e,0xf1,0x93,0x4f,0x20,0x8d, - 0x03,0x0a,0x9f,0x60,0x23,0xd8,0x31,0xf5,0x3b,0x5d,0x00,0xca,0x20,0x8d, - 0x03,0x0a,0x9f,0xd2,0xb0,0x27,0xc6,0x36,0x2f,0xf9,0x76,0xb8,0x20,0x8d, - 0x03,0x0a,0x98,0x3d,0x24,0x92,0x18,0x0e,0xbe,0x5e,0x37,0x80,0x20,0x8d, - 0x03,0x0a,0x98,0x2b,0xfa,0x4d,0xf6,0xe3,0xcb,0x8f,0xa7,0xca,0x20,0x8d, - 0x03,0x0a,0x98,0x2e,0x6e,0xe7,0x52,0xb9,0x59,0xd1,0x70,0x7e,0x20,0x8d, - 0x03,0x0a,0x99,0x15,0x6a,0xb4,0x2e,0x18,0x73,0x15,0xd0,0xb2,0x20,0x8d, - 0x03,0x0a,0x99,0xb9,0x4b,0x45,0x2c,0x9c,0x74,0x95,0x85,0x38,0x20,0x8d, - 0x03,0x0a,0x99,0xf8,0x24,0xd4,0xa5,0x4c,0xed,0xea,0xb9,0x94,0x20,0x8d, - 0x03,0x0a,0x99,0xfc,0x5b,0xe1,0x93,0xb3,0x4a,0x82,0xc0,0x94,0x20,0x8d, - 0x03,0x0a,0x99,0xe6,0x23,0x9d,0x7a,0xed,0x35,0xe6,0x99,0x70,0x20,0x8d, - 0x03,0x0a,0x9a,0x10,0x03,0xfc,0x52,0xa3,0x94,0xb1,0x55,0x1e,0x20,0x8d, - 0x03,0x0a,0x9a,0xbd,0xbb,0xf4,0xaa,0xde,0xf7,0xfc,0xee,0x83,0x20,0x8d, - 0x03,0x0a,0x9a,0x8c,0xe7,0x4c,0x13,0xf0,0xa0,0xdf,0xd7,0x18,0x20,0x8d, - 0x03,0x0a,0x9b,0x53,0xdf,0x76,0xd6,0x86,0x7b,0x67,0xa6,0xb2,0x20,0x8d, - 0x03,0x0a,0x9c,0xbd,0x0b,0xef,0xec,0x63,0xe9,0xe6,0xa7,0xb8,0x20,0x8d, - 0x03,0x0a,0x9c,0xd2,0x89,0x56,0xf8,0x19,0x83,0x37,0xf7,0xc5,0x20,0x8d, - 0x03,0x0a,0x9d,0x9b,0xde,0x57,0xf1,0x06,0xae,0x93,0x0f,0xbd,0x20,0x8d, - 0x03,0x0a,0x9d,0xc8,0xce,0xb0,0x94,0x36,0xb8,0x6d,0x13,0x23,0x20,0x8d, - 0x03,0x0a,0x9e,0x11,0x46,0xb7,0x7e,0x5b,0x0a,0x28,0x75,0x71,0x20,0x8d, - 0x03,0x0a,0x9e,0x2b,0xdf,0x5e,0x5e,0x37,0x9a,0x3c,0xc2,0x97,0x20,0x8d, - 0x03,0x0a,0xa7,0x3e,0x5d,0x9e,0xf6,0x87,0xbb,0x23,0x4b,0x8e,0x20,0x8d, - 0x03,0x0a,0xa7,0x23,0xf2,0xb4,0xee,0x5c,0x47,0x6b,0x2d,0xa8,0x20,0x8d, - 0x03,0x0a,0xa7,0x7b,0xe7,0x14,0x3b,0x66,0x01,0x10,0x16,0xcd,0x20,0x8d, - 0x03,0x0a,0xa7,0x61,0xb3,0x07,0x3c,0x83,0xf3,0xcb,0x55,0x71,0x20,0x8d, - 0x03,0x0a,0xa0,0x14,0xbc,0x6f,0x03,0x89,0x2b,0x57,0xde,0xc8,0x20,0x8d, - 0x03,0x0a,0xa1,0xbc,0x70,0x3d,0x1c,0x84,0xc8,0xac,0x8b,0xf5,0x20,0x8d, - 0x03,0x0a,0xa2,0x3b,0xdd,0xc1,0xd3,0x1f,0xa2,0xe6,0xee,0x25,0x20,0x8d, - 0x03,0x0a,0xa2,0x23,0xf2,0xee,0xcb,0x9b,0x94,0x0f,0x04,0x21,0x20,0x8d, - 0x03,0x0a,0xa2,0xa2,0x94,0x9e,0xce,0x1a,0xf9,0xcb,0x31,0xc5,0x20,0x8d, - 0x03,0x0a,0xa2,0xfa,0x66,0x69,0x17,0xc7,0xd5,0x01,0x96,0xc6,0x20,0x8d, - 0x03,0x0a,0xa3,0x46,0x3f,0xc6,0x49,0xe3,0xc8,0xdd,0xd9,0xdc,0x20,0x8d, - 0x03,0x0a,0xa3,0xa3,0x67,0xe4,0xa4,0x3c,0xf0,0xa8,0x9b,0x9b,0x20,0x8d, - 0x03,0x0a,0xa3,0xab,0x27,0xeb,0x0b,0x9b,0x40,0xe4,0xc3,0xcb,0x20,0x8d, - 0x03,0x0a,0xa4,0x81,0x96,0x0c,0x52,0xde,0x9b,0x8d,0x70,0x78,0x20,0x8d, - 0x03,0x0a,0xa4,0x81,0x99,0x7c,0xcb,0x67,0xcc,0x4c,0x5d,0x4b,0x20,0x8d, - 0x03,0x0a,0xa4,0xa5,0xa5,0x10,0x66,0xfc,0x15,0x63,0x0e,0x3d,0x20,0x8d, - 0x03,0x0a,0xa4,0xcd,0x88,0xd6,0xdf,0xed,0xab,0xa6,0xe1,0x88,0x20,0x8d, - 0x03,0x0a,0xa6,0x6c,0x01,0x32,0x5f,0x56,0x32,0x72,0x1c,0x2b,0x20,0x8d, - 0x03,0x0a,0xae,0x94,0x31,0x12,0x75,0x92,0xd8,0x32,0x8a,0xd1,0x20,0x8d, - 0x03,0x0a,0xaf,0x56,0x76,0xe7,0x35,0xf3,0x5a,0x62,0x9b,0xa3,0x20,0x8d, - 0x03,0x0a,0xa8,0xb9,0xc3,0x07,0x95,0x23,0xde,0xe0,0xc6,0x7b,0x20,0x8d, - 0x03,0x0a,0xa9,0x6d,0x83,0xa6,0x9c,0xdd,0xae,0x7c,0xd6,0x97,0x20,0x8d, - 0x03,0x0a,0xa9,0xa8,0x9a,0x15,0x5d,0xda,0xe1,0x87,0x2d,0x0e,0x20,0x8d, - 0x03,0x0a,0xa9,0xc8,0x44,0xc2,0x1a,0xaf,0x46,0xa0,0xf2,0xf1,0x20,0x8d, - 0x03,0x0a,0xaa,0x7d,0xc2,0x0c,0x95,0xe2,0x5b,0x02,0x8e,0x41,0x20,0x8d, - 0x03,0x0a,0xab,0x00,0x8e,0xd1,0x06,0x26,0x63,0xa5,0x1d,0x49,0x20,0x8d, - 0x03,0x0a,0xab,0x29,0x85,0x0f,0xf2,0xb8,0x58,0x8f,0xdb,0xbf,0x20,0x8d, - 0x03,0x0a,0xab,0x98,0x40,0x0a,0x73,0x43,0x6f,0xb6,0x3d,0x8b,0x20,0x8d, - 0x03,0x0a,0xab,0xdd,0x6d,0x5d,0xc5,0x36,0xcb,0x6c,0xc8,0x70,0x20,0x8d, - 0x03,0x0a,0xac,0x81,0x65,0xa3,0x8b,0xea,0x0b,0x71,0xe4,0x16,0x20,0x8d, - 0x03,0x0a,0xad,0x1b,0x40,0xc1,0x45,0x64,0xbf,0x24,0x15,0xca,0x20,0x8d, - 0x03,0x0a,0xad,0x1c,0xc0,0xb4,0x95,0xb5,0x17,0xc0,0xc2,0x41,0x20,0x8d, - 0x03,0x0a,0xad,0xc4,0xfa,0x8d,0xa6,0xf7,0x40,0x42,0xe7,0xd3,0x20,0x8d, - 0x03,0x0a,0xae,0x2e,0xe4,0x64,0x79,0x05,0x5f,0xb7,0x04,0x14,0x20,0x8d, - 0x03,0x0a,0xb0,0x48,0xe6,0xe8,0x48,0xfa,0xca,0x87,0x78,0x18,0x20,0x8d, - 0x03,0x0a,0xb0,0x6c,0x4a,0x92,0xde,0xd3,0x0d,0x28,0xc4,0x79,0x20,0x8d, - 0x03,0x0a,0xb1,0x41,0x81,0xac,0xde,0xce,0x0b,0x94,0x8a,0x9d,0x20,0x8d, - 0x03,0x0a,0xb1,0x73,0xdf,0x4b,0xab,0xc3,0x7a,0x3c,0x48,0x99,0x20,0x8d, - 0x03,0x0a,0xb1,0xb6,0xc8,0x72,0x86,0xc6,0x34,0x6b,0xef,0x41,0x20,0x8d, - 0x03,0x0a,0xb1,0xd5,0x8e,0xf0,0x22,0x9a,0x8b,0xa6,0xf1,0xfb,0x20,0x8d, - 0x03,0x0a,0xb1,0xd8,0x90,0x36,0x0e,0xc6,0x51,0x9c,0x8b,0x93,0x20,0x8d, - 0x03,0x0a,0xb2,0xce,0xea,0x6a,0xd7,0x34,0x30,0x8d,0xdf,0x65,0x20,0x8d, - 0x03,0x0a,0xb2,0xea,0xa2,0xc5,0xeb,0x2a,0x10,0xec,0xeb,0x4e,0x20,0x8d, - 0x03,0x0a,0xbe,0xda,0x60,0xee,0xa0,0xf8,0xdd,0x5a,0x11,0xb6,0x20,0x8d, - 0x03,0x0a,0xbf,0x7f,0x7f,0x68,0x2c,0x63,0x70,0xba,0xbb,0xf1,0x20,0x8d, - 0x03,0x0a,0xb9,0xaa,0xce,0xfd,0x87,0x35,0x7b,0xee,0x0d,0x40,0x20,0x8d, - 0x03,0x0a,0xb9,0xe5,0xb3,0x2c,0xb6,0x6d,0x91,0x46,0x22,0xad,0x20,0x8d, - 0x03,0x0a,0xba,0x49,0xd2,0xda,0xb8,0x28,0xe8,0x4d,0x53,0xca,0x20,0x8d, - 0x03,0x0a,0xba,0xcd,0x40,0x9b,0x0b,0xc6,0x82,0xba,0xc8,0xdd,0x20,0x8d, - 0x03,0x0a,0xbb,0x57,0x4d,0xce,0xa0,0x53,0x4d,0x8f,0xcd,0x4f,0x20,0x8d, - 0x03,0x0a,0xbb,0xba,0xc0,0x45,0x0b,0x3d,0x30,0xef,0x86,0x93,0x20,0x8d, - 0x03,0x0a,0xbc,0x80,0x0b,0xa0,0xe3,0xc1,0x9b,0x6b,0xc5,0x17,0x20,0x8d, - 0x03,0x0a,0xbd,0x3a,0xc5,0xd0,0xc3,0x93,0x32,0x55,0x57,0x27,0x20,0x8d, - 0x03,0x0a,0xbd,0x63,0x78,0x09,0xf3,0x85,0x50,0x42,0x0c,0x3a,0x20,0x8d, - 0x03,0x0a,0xbd,0xb2,0x78,0xc7,0x06,0x2c,0xe1,0xb8,0x72,0xdc,0x20,0x8d, - 0x03,0x0a,0xc7,0x25,0x66,0x48,0x17,0x18,0x9d,0x2d,0x05,0xb4,0x20,0x8d, - 0x03,0x0a,0xc7,0x66,0xbe,0x2e,0x08,0xdf,0xba,0xf7,0xae,0x83,0x20,0x8d, - 0x03,0x0a,0xc7,0x6d,0x92,0x43,0x00,0x24,0xe5,0xd6,0x83,0xd3,0x20,0x8d, - 0x03,0x0a,0xc7,0xf7,0x05,0x69,0x99,0x52,0x54,0x77,0x2b,0x1f,0x20,0x8d, - 0x03,0x0a,0xc7,0xdd,0x9d,0xe0,0x6d,0xaa,0x03,0xcb,0x9c,0x21,0x20,0x8d, - 0x03,0x0a,0xc0,0x0f,0xf8,0x18,0xb0,0x84,0x66,0x47,0x08,0xe4,0x20,0x8d, - 0x03,0x0a,0xc0,0x41,0xc0,0xc5,0x9d,0xef,0x46,0x46,0xae,0x7f,0x20,0x8d, - 0x03,0x0a,0xc1,0x89,0x05,0x1b,0x88,0x6b,0xd7,0x20,0x08,0x9b,0x20,0x8d, - 0x03,0x0a,0xc2,0x4e,0xd2,0xd3,0xfd,0x58,0x32,0x14,0x6f,0x87,0x20,0x8d, - 0x03,0x0a,0xc2,0x6d,0xf5,0x40,0x0f,0xbd,0xfb,0x53,0x19,0xc9,0x20,0x8d, - 0x03,0x0a,0xc3,0x3e,0x86,0xb1,0xd5,0x0c,0x5a,0x0e,0x18,0x4e,0x20,0x8d, - 0x03,0x0a,0xc4,0x3a,0x2a,0x49,0xb4,0x72,0xa4,0x2c,0x7b,0x99,0x20,0x8d, - 0x03,0x0a,0xc4,0x44,0x04,0x3a,0x11,0x84,0x47,0x67,0x2a,0x13,0x20,0x8d, - 0x03,0x0a,0xc4,0x45,0x1f,0xbc,0xc9,0xa0,0x32,0x01,0xeb,0xbc,0x20,0x8d, - 0x03,0x0a,0xc4,0x55,0x2a,0xb9,0xbb,0x9b,0x2a,0xe7,0x1c,0x75,0x20,0x8d, - 0x03,0x0a,0xc4,0xdf,0x49,0x72,0xb7,0xed,0xbe,0x9f,0x59,0xfa,0x20,0x8d, - 0x03,0x0a,0xc4,0xe0,0x24,0x19,0x5a,0x39,0xc6,0xbe,0x74,0xee,0x20,0x8d, - 0x03,0x0a,0xc5,0xdc,0x95,0xee,0xec,0x4d,0x25,0xb1,0xa1,0x5a,0x20,0x8d, - 0x03,0x0a,0xc6,0x47,0x01,0xca,0x17,0xe1,0x47,0x46,0x9b,0xd6,0x20,0x8d, - 0x03,0x0a,0xce,0xf6,0xda,0x2a,0x7f,0x69,0x90,0xad,0x89,0xe4,0x20,0x8d, - 0x03,0x0a,0xce,0xf1,0x60,0x80,0x76,0xe7,0x9a,0x36,0xdc,0xc7,0x20,0x8d, - 0x03,0x0a,0xcf,0x98,0x18,0x43,0xeb,0x5d,0xd7,0x16,0xf1,0x50,0x20,0x8d, - 0x03,0x0a,0xc8,0x76,0xb8,0x89,0x52,0x6f,0x23,0x93,0xe5,0x24,0x20,0x8d, - 0x03,0x0a,0xc9,0x3e,0xe1,0xbf,0xef,0xc8,0x22,0x97,0xae,0x51,0x20,0x8d, - 0x03,0x0a,0xc9,0x82,0xc3,0xcc,0x29,0x07,0x0b,0x8d,0x6f,0xfb,0x20,0x8d, - 0x03,0x0a,0xc9,0xfe,0x7a,0x81,0x62,0x35,0x52,0xf7,0x02,0x0c,0x20,0x8d, - 0x03,0x0a,0xca,0x33,0x3a,0xdc,0x87,0x62,0x7a,0xc2,0x1d,0xe6,0x20,0x8d, - 0x03,0x0a,0xca,0x50,0x8d,0xe0,0x82,0x1c,0x59,0x0f,0xef,0x1b,0x20,0x8d, - 0x03,0x0a,0xca,0xa3,0x66,0x19,0x34,0xac,0xb2,0x0f,0x60,0x9a,0x20,0x8d, - 0x03,0x0a,0xcb,0xb3,0xa0,0x39,0xf6,0x46,0xec,0x5a,0x42,0xc6,0x20,0x8d, - 0x03,0x0a,0xcc,0xc6,0x22,0xb4,0xfc,0xf7,0xff,0xb0,0xa2,0xb4,0x20,0x8d, - 0x03,0x0a,0xcd,0x2e,0x71,0x78,0x7b,0x6d,0x9e,0x61,0x70,0x05,0x20,0x8d, - 0x03,0x0a,0xcd,0x31,0x38,0x94,0x95,0xca,0x44,0xf4,0x65,0x68,0x20,0x8d, - 0x03,0x0a,0xcd,0x61,0xe1,0xbe,0x7b,0x46,0x9c,0x51,0xbf,0x66,0x20,0x8d, - 0x03,0x0a,0xcd,0xac,0xcf,0x18,0x1f,0xa6,0x8f,0x02,0x6a,0x43,0x20,0x8d, - 0x03,0x0a,0xce,0x20,0x1e,0x2c,0x8d,0x2c,0x9e,0xd9,0xa7,0xac,0x20,0x8d, 0x04,0x20,0xd1,0xbb,0x02,0x8d,0x4d,0xd5,0x6a,0x20,0xc0,0xf9,0x16,0x2b,0x84,0x22,0x66,0xe0,0x89,0x45,0x60,0x37,0x52,0xe2,0x0b,0xa5,0xb4,0xf8,0x26,0xb3,0x8f,0x5a,0x30,0xed,0x20,0x8d, 0x04,0x20,0xd2,0x59,0x3b,0xd7,0x14,0x7e,0xd0,0x98,0xfe,0x9e,0xa5,0x69,0xf4,0x26,0x6d,0x72,0x6f,0xc3,0x76,0xce,0x1d,0x40,0x41,0xa2,0xa1,0xaf,0xf9,0x6e,0x57,0x2d,0x9d,0xc3,0x20,0x8d, 0x04,0x20,0xdf,0xd9,0xed,0x59,0xbf,0x1e,0x77,0x48,0x3c,0x13,0x3b,0xc5,0xc8,0x15,0x86,0x88,0x68,0xf0,0x08,0xe9,0xee,0x9b,0x3d,0xa4,0x33,0x0a,0x68,0x67,0x86,0x9d,0xe2,0x83,0x20,0x8d, diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index e78dc9f2a5..d5fd43e131 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -24,7 +24,7 @@ namespace Consensus { * @param[out] txfee Set to the transaction fee if successful. * Preconditions: tx.IsCoinBase() is false. */ -bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); +[[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); } // namespace Consensus /** Auxiliary functions for transaction validation (ideally should not be exposed) */ diff --git a/src/index/base.cpp b/src/index/base.cpp index 4079fc4569..3a61af28b7 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -60,33 +60,34 @@ bool BaseIndex::Init() } LOCK(cs_main); + CChain& active_chain = m_chainstate->m_chain; if (locator.IsNull()) { m_best_block_index = nullptr; } else { - m_best_block_index = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); + m_best_block_index = m_chainstate->m_blockman.FindForkInGlobalIndex(active_chain, locator); } - m_synced = m_best_block_index.load() == ::ChainActive().Tip(); + m_synced = m_best_block_index.load() == active_chain.Tip(); if (!m_synced) { bool prune_violation = false; if (!m_best_block_index) { // index is not built yet // make sure we have all block data back to the genesis - const CBlockIndex* block = ::ChainActive().Tip(); + const CBlockIndex* block = active_chain.Tip(); while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { block = block->pprev; } - prune_violation = block != ::ChainActive().Genesis(); + prune_violation = block != active_chain.Genesis(); } // in case the index has a best block set and is not fully synced // check if we have the required blocks to continue building the index else { const CBlockIndex* block_to_test = m_best_block_index.load(); - if (!ChainActive().Contains(block_to_test)) { + if (!active_chain.Contains(block_to_test)) { // if the bestblock is not part of the mainchain, find the fork // and make sure we have all data down to the fork - block_to_test = ::ChainActive().FindFork(block_to_test); + block_to_test = active_chain.FindFork(block_to_test); } - const CBlockIndex* block = ::ChainActive().Tip(); + const CBlockIndex* block = active_chain.Tip(); prune_violation = true; // check backwards from the tip if we have all block data until we reach the indexes bestblock while (block_to_test && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { @@ -104,20 +105,20 @@ bool BaseIndex::Init() return true; } -static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain& chain) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); if (!pindex_prev) { - return ::ChainActive().Genesis(); + return chain.Genesis(); } - const CBlockIndex* pindex = ::ChainActive().Next(pindex_prev); + const CBlockIndex* pindex = chain.Next(pindex_prev); if (pindex) { return pindex; } - return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev)); + return chain.Next(chain.FindFork(pindex_prev)); } void BaseIndex::ThreadSync() @@ -140,7 +141,7 @@ void BaseIndex::ThreadSync() { LOCK(cs_main); - const CBlockIndex* pindex_next = NextSyncBlock(pindex); + const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain); if (!pindex_next) { m_best_block_index = pindex; m_synced = true; @@ -203,7 +204,7 @@ bool BaseIndex::Commit() bool BaseIndex::CommitInternal(CDBBatch& batch) { LOCK(cs_main); - GetDB().WriteBestBlock(batch, ::ChainActive().GetLocator(m_best_block_index)); + GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index)); return true; } @@ -279,7 +280,7 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator) const CBlockIndex* locator_tip_index; { LOCK(cs_main); - locator_tip_index = g_chainman.m_blockman.LookupBlockIndex(locator_tip_hash); + locator_tip_index = m_chainstate->m_blockman.LookupBlockIndex(locator_tip_hash); } if (!locator_tip_index) { @@ -320,7 +321,7 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() const // Skip the queue-draining stuff if we know we're caught up with // ::ChainActive().Tip(). LOCK(cs_main); - const CBlockIndex* chain_tip = ::ChainActive().Tip(); + const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip(); const CBlockIndex* best_block_index = m_best_block_index.load(); if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) { return true; @@ -337,8 +338,10 @@ void BaseIndex::Interrupt() m_interrupt(); } -bool BaseIndex::Start() +bool BaseIndex::Start(CChainState& active_chainstate) { + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + m_chainstate = &active_chainstate; // Need to register this ValidationInterface before running Init(), so that // callbacks are not missed if Init sets m_synced to true. RegisterValidationInterface(this); diff --git a/src/index/base.h b/src/index/base.h index 59eefab29e..df4bdff1ea 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -12,6 +12,7 @@ #include <validationinterface.h> class CBlockIndex; +class CChainState; struct IndexSummary { std::string name; @@ -75,8 +76,9 @@ private: /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up /// getting corrupted. bool Commit(); - protected: + CChainState* m_chainstate{nullptr}; + void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override; void ChainStateFlushed(const CBlockLocator& locator) override; @@ -117,7 +119,7 @@ public: /// Start initializes the sync state and registers the instance as a /// ValidationInterface so that it stays in sync with blockchain updates. - [[nodiscard]] bool Start(); + [[nodiscard]] bool Start(CChainState& active_chainstate); /// Stops the instance from staying in sync with blockchain updates. void Stop(); diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index e046527283..8c6046489b 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -266,7 +266,7 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n { LOCK(cs_main); - CBlockIndex* iter_tip{g_chainman.m_blockman.LookupBlockIndex(current_tip->GetBlockHash())}; + CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())}; const auto& consensus_params{Params().GetConsensus()}; do { diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index d9e437ad10..782e557478 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -204,7 +204,7 @@ bool TxIndex::Init() // Attempt to migrate txindex from the old database to the new one. Even if // chain_tip is null, the node could be reindexing and we still want to // delete txindex records in the old database. - if (!m_db->MigrateData(*pblocktree, ::ChainActive().GetLocator())) { + if (!m_db->MigrateData(*pblocktree, m_chainstate->m_chain.GetLocator())) { return false; } diff --git a/src/init.cpp b/src/init.cpp index a835df0572..7f64b1acfa 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1549,21 +1549,21 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex); - if (!g_txindex->Start()) { + if (!g_txindex->Start(::ChainstateActive())) { return false; } } for (const auto& filter_type : g_enabled_filter_types) { InitBlockFilterIndex(filter_type, filter_index_cache, false, fReindex); - if (!GetBlockFilterIndex(filter_type)->Start()) { + if (!GetBlockFilterIndex(filter_type)->Start(::ChainstateActive())) { return false; } } if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) { g_coin_stats_index = std::make_unique<CoinStatsIndex>(/* cache size */ 0, false, fReindex); - if (!g_coin_stats_index->Start()) { + if (!g_coin_stats_index->Start(::ChainstateActive())) { return false; } } diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 6ccfd7fc20..88f93321f9 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -112,14 +112,11 @@ public: //! Get wallet address list. virtual std::vector<WalletAddress> getAddresses() = 0; - //! Add dest data. - virtual bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) = 0; + //! Get receive requests. + virtual std::vector<std::string> getAddressReceiveRequests() = 0; - //! Erase dest data. - virtual bool eraseDestData(const CTxDestination& dest, const std::string& key) = 0; - - //! Get dest values with prefix. - virtual std::vector<std::string> getDestValues(const std::string& prefix) = 0; + //! Save or remove receive request. + virtual bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) = 0; //! Lock coin. virtual void lockCoin(const COutPoint& output) = 0; diff --git a/src/key_io.cpp b/src/key_io.cpp index dbcbfa1f29..615f4c9312 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -54,6 +54,14 @@ public: return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data); } + std::string operator()(const WitnessV1Taproot& tap) const + { + std::vector<unsigned char> data = {1}; + data.reserve(53); + ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, tap.begin(), tap.end()); + return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data); + } + std::string operator()(const WitnessUnknown& id) const { if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) { @@ -135,6 +143,13 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return CNoDestination(); } + if (version == 1 && data.size() == WITNESS_V1_TAPROOT_SIZE) { + static_assert(WITNESS_V1_TAPROOT_SIZE == WitnessV1Taproot::size()); + WitnessV1Taproot tap; + std::copy(data.begin(), data.end(), tap.begin()); + return tap; + } + if (version > 16) { error_str = "Invalid Bech32 address witness version"; return CNoDestination(); diff --git a/src/miner.cpp b/src/miner.cpp index 3bc7fdd458..eccddbb04f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -39,13 +39,21 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam return nNewTime - nOldTime; } -void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block) +void RegenerateCommitments(CBlock& block, ChainstateManager& chainman) { CMutableTransaction tx{*block.vtx.at(0)}; tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block)); block.vtx.at(0) = MakeTransactionRef(tx); - WITH_LOCK(::cs_main, assert(g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock) == prev_block)); + CBlockIndex* prev_block; + { + // TODO: Temporary scope to check correctness of refactored code. + // Should be removed manually after merge of + // https://github.com/bitcoin/bitcoin/pull/20158 + LOCK(::cs_main); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(chainman.m_blockman)); + prev_block = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock); + } GenerateCoinbaseCommitment(block, prev_block, Params().GetConsensus()); block.hashMerkleRoot = BlockMerkleRoot(block); diff --git a/src/miner.h b/src/miner.h index becf362b79..10a80f4392 100644 --- a/src/miner.h +++ b/src/miner.h @@ -203,6 +203,6 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ -void RegenerateCommitments(CBlock& block, CBlockIndex* prev_block); +void RegenerateCommitments(CBlock& block, ChainstateManager& chainman); #endif // BITCOIN_MINER_H diff --git a/src/net.cpp b/src/net.cpp index 1b6f04dead..6f9f17ed4e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -796,7 +796,7 @@ size_t CConnman::SocketSendData(CNode& node) const nBytes = send(node.hSocket, reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); } if (nBytes > 0) { - node.nLastSend = GetSystemTimeInSeconds(); + node.nLastSend = GetTimeSeconds(); node.nSendBytes += nBytes; node.nSendOffset += nBytes; nSentSize += nBytes; @@ -1251,7 +1251,7 @@ void CConnman::NotifyNumConnectionsChanged() bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::optional<int64_t> now_in) const { - const int64_t now = now_in ? now_in.value() : GetSystemTimeInSeconds(); + const int64_t now = now_in ? now_in.value() : GetTimeSeconds(); return node.nTimeConnected + m_peer_connect_timeout < now; } @@ -1259,7 +1259,7 @@ bool CConnman::InactivityCheck(const CNode& node) const { // Use non-mockable system time (otherwise these timers will pop when we // use setmocktime in the tests). - int64_t now = GetSystemTimeInSeconds(); + int64_t now = GetTimeSeconds(); if (!ShouldRunInactivityChecks(node, now)) return false; @@ -2912,7 +2912,7 @@ ServiceFlags CConnman::GetLocalServices() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion) - : nTimeConnected(GetSystemTimeInSeconds()), + : nTimeConnected(GetTimeSeconds()), addr(addrIn), addrBind(addrBindIn), m_inbound_onion(inbound_onion), @@ -3048,7 +3048,7 @@ void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Spa ser_writedata64(f, now.count()); f.write(msg_type.data(), msg_type.length()); for (auto i = msg_type.length(); i < CMessageHeader::COMMAND_SIZE; ++i) { - f << '\0'; + f << uint8_t{'\0'}; } uint32_t size = data.size(); ser_writedata32(f, size); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0b83f756b3..65224b4259 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -491,7 +491,8 @@ private: void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main); - void ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing); + /** Process a new block. Perform any post-processing housekeeping */ + void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing); /** Relay map (txid or wtxid -> CTransactionRef) */ typedef std::map<uint256, CTransactionRef> MapRelay; @@ -2384,15 +2385,15 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv) m_connman.PushMessage(&peer, std::move(msg)); } -void PeerManagerImpl::ProcessBlock(CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing) +void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing) { - bool fNewBlock = false; - m_chainman.ProcessNewBlock(m_chainparams, pblock, fForceProcessing, &fNewBlock); - if (fNewBlock) { - pfrom.nLastBlockTime = GetTime(); + bool new_block{false}; + m_chainman.ProcessNewBlock(m_chainparams, block, force_processing, &new_block); + if (new_block) { + node.nLastBlockTime = GetTime(); } else { LOCK(cs_main); - mapBlockSource.erase(pblock->GetHash()); + mapBlockSource.erase(block->GetHash()); } } @@ -3475,7 +3476,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, LOCK(cs_main); mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.GetId(), false)); } - // Setting fForceProcessing to true means that we bypass some of + // Setting force_processing to true means that we bypass some of // our anti-DoS protections in AcceptBlock, which filters // unrequested blocks that might be trying to waste our resources // (eg disk space). Because we only try to reconstruct blocks when @@ -3484,7 +3485,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // we have a chain with at least nMinimumChainWork), and we ignore // compact blocks with less work than our tip, it is safe to treat // reconstructed compact blocks as having been requested. - ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true); + ProcessBlock(pfrom, pblock, /*force_processing=*/true); LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid() if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) { // Clear download state for this block, which is in @@ -3567,7 +3568,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // disk-space attacks), but this should be safe due to the // protections in the compact block handler -- see related comment // in compact block optimistic reconstruction handling. - ProcessBlock(pfrom, pblock, /*fForceProcessing=*/true); + ProcessBlock(pfrom, pblock, /*force_processing=*/true); } return; } diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 352abae298..0ae8dd0698 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -32,14 +32,7 @@ CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const case NET_IPV6: return BIP155Network::IPV6; case NET_ONION: - switch (m_addr.size()) { - case ADDR_TORV2_SIZE: - return BIP155Network::TORV2; - case ADDR_TORV3_SIZE: - return BIP155Network::TORV3; - default: - assert(false); - } + return BIP155Network::TORV3; case NET_I2P: return BIP155Network::I2P; case NET_CJDNS: @@ -72,14 +65,6 @@ bool CNetAddr::SetNetFromBIP155Network(uint8_t possible_bip155_net, size_t addre throw std::ios_base::failure( strprintf("BIP155 IPv6 address with length %u (should be %u)", address_size, ADDR_IPV6_SIZE)); - case BIP155Network::TORV2: - if (address_size == ADDR_TORV2_SIZE) { - m_net = NET_ONION; - return true; - } - throw std::ios_base::failure( - strprintf("BIP155 TORv2 address with length %u (should be %u)", address_size, - ADDR_TORV2_SIZE)); case BIP155Network::TORV3: if (address_size == ADDR_TORV3_SIZE) { m_net = NET_ONION; @@ -130,7 +115,7 @@ void CNetAddr::SetIP(const CNetAddr& ipIn) assert(ipIn.m_addr.size() == ADDR_IPV6_SIZE); break; case NET_ONION: - assert(ipIn.m_addr.size() == ADDR_TORV2_SIZE || ipIn.m_addr.size() == ADDR_TORV3_SIZE); + assert(ipIn.m_addr.size() == ADDR_TORV3_SIZE); break; case NET_I2P: assert(ipIn.m_addr.size() == ADDR_I2P_SIZE); @@ -161,9 +146,12 @@ void CNetAddr::SetLegacyIPv6(Span<const uint8_t> ipv6) m_net = NET_IPV4; skip = sizeof(IPV4_IN_IPV6_PREFIX); } else if (HasPrefix(ipv6, TORV2_IN_IPV6_PREFIX)) { - // TORv2-in-IPv6 - m_net = NET_ONION; - skip = sizeof(TORV2_IN_IPV6_PREFIX); + // TORv2-in-IPv6 (unsupported). Unserialize as !IsValid(), thus ignoring them. + // Mimic a default-constructed CNetAddr object which is !IsValid() and thus + // will not be gossiped, but continue reading next addresses from the stream. + m_net = NET_IPV6; + m_addr.assign(ADDR_IPV6_SIZE, 0x0); + return; } else if (HasPrefix(ipv6, INTERNAL_IN_IPV6_PREFIX)) { // Internal-in-IPv6 m_net = NET_INTERNAL; @@ -254,12 +242,7 @@ bool CNetAddr::SetTor(const std::string& addr) return false; } - switch (input.size()) { - case ADDR_TORV2_SIZE: - m_net = NET_ONION; - m_addr.assign(input.begin(), input.end()); - return true; - case torv3::TOTAL_LEN: { + if (input.size() == torv3::TOTAL_LEN) { Span<const uint8_t> input_pubkey{input.data(), ADDR_TORV3_SIZE}; Span<const uint8_t> input_checksum{input.data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN}; Span<const uint8_t> input_version{input.data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)}; @@ -279,7 +262,6 @@ bool CNetAddr::SetTor(const std::string& addr) m_addr.assign(input_pubkey.begin(), input_pubkey.end()); return true; } - } return false; } @@ -528,7 +510,6 @@ bool CNetAddr::IsAddrV1Compatible() const case NET_INTERNAL: return true; case NET_ONION: - return m_addr.size() == ADDR_TORV2_SIZE; case NET_I2P: case NET_CJDNS: return false; @@ -613,33 +594,26 @@ static std::string IPv6ToString(Span<const uint8_t> a, uint32_t scope_id) return r; } +static std::string OnionToString(const Span<const uint8_t>& addr) +{ + uint8_t checksum[torv3::CHECKSUM_LEN]; + torv3::Checksum(addr, checksum); + // TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion" + prevector<torv3::TOTAL_LEN, uint8_t> address{addr.begin(), addr.end()}; + address.insert(address.end(), checksum, checksum + torv3::CHECKSUM_LEN); + address.insert(address.end(), torv3::VERSION, torv3::VERSION + sizeof(torv3::VERSION)); + return EncodeBase32(address) + ".onion"; +} + std::string CNetAddr::ToStringIP() const { switch (m_net) { case NET_IPV4: return IPv4ToString(m_addr); - case NET_IPV6: { + case NET_IPV6: return IPv6ToString(m_addr, m_scope_id); - } case NET_ONION: - switch (m_addr.size()) { - case ADDR_TORV2_SIZE: - return EncodeBase32(m_addr) + ".onion"; - case ADDR_TORV3_SIZE: { - - uint8_t checksum[torv3::CHECKSUM_LEN]; - torv3::Checksum(m_addr, checksum); - - // TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion" - prevector<torv3::TOTAL_LEN, uint8_t> address{m_addr.begin(), m_addr.end()}; - address.insert(address.end(), checksum, checksum + torv3::CHECKSUM_LEN); - address.insert(address.end(), torv3::VERSION, torv3::VERSION + sizeof(torv3::VERSION)); - - return EncodeBase32(address) + ".onion"; - } - default: - assert(false); - } + return OnionToString(m_addr); case NET_I2P: return EncodeBase32(m_addr, false /* don't pad with = */) + ".b32.i2p"; case NET_CJDNS: diff --git a/src/netaddress.h b/src/netaddress.h index 897ce46cda..0d04ab88fb 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -97,9 +97,6 @@ static constexpr size_t ADDR_IPV4_SIZE = 4; /// Size of IPv6 address (in bytes). static constexpr size_t ADDR_IPV6_SIZE = 16; -/// Size of TORv2 address (in bytes). -static constexpr size_t ADDR_TORV2_SIZE = 10; - /// Size of TORv3 address (in bytes). This is the length of just the address /// as used in BIP155, without the checksum and the version byte. static constexpr size_t ADDR_TORV3_SIZE = 32; @@ -260,8 +257,7 @@ class CNetAddr /** * Parse a Tor address and set this object to it. * @param[in] addr Address to parse, must be a valid C string, for example - * pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion or - * 6hzph5hv6337r6p2.onion. + * pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion. * @returns Whether the operation was successful. * @see CNetAddr::IsTor() */ @@ -303,7 +299,7 @@ class CNetAddr /** * Get the BIP155 network id of this address. * Must not be called for IsInternal() objects. - * @returns BIP155 network id + * @returns BIP155 network id, except TORV2 which is no longer supported. */ BIP155Network GetBIP155Network() const; @@ -334,23 +330,14 @@ class CNetAddr memcpy(arr, IPV4_IN_IPV6_PREFIX.data(), prefix_size); memcpy(arr + prefix_size, m_addr.data(), m_addr.size()); return; - case NET_ONION: - if (m_addr.size() == ADDR_TORV3_SIZE) { - break; - } - prefix_size = sizeof(TORV2_IN_IPV6_PREFIX); - assert(prefix_size + m_addr.size() == sizeof(arr)); - memcpy(arr, TORV2_IN_IPV6_PREFIX.data(), prefix_size); - memcpy(arr + prefix_size, m_addr.data(), m_addr.size()); - return; case NET_INTERNAL: prefix_size = sizeof(INTERNAL_IN_IPV6_PREFIX); assert(prefix_size + m_addr.size() == sizeof(arr)); memcpy(arr, INTERNAL_IN_IPV6_PREFIX.data(), prefix_size); memcpy(arr + prefix_size, m_addr.data(), m_addr.size()); return; + case NET_ONION: case NET_I2P: - break; case NET_CJDNS: break; case NET_UNROUTABLE: @@ -358,7 +345,7 @@ class CNetAddr assert(false); } // no default case, so the compiler can warn about missing cases - // Serialize TORv3, I2P and CJDNS as all-zeros. + // Serialize ONION, I2P and CJDNS as all-zeros. memset(arr, 0x0, V1_SERIALIZATION_SIZE); } diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 334acb454e..51cc826b00 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -180,6 +180,12 @@ XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes) std::copy(bytes.begin(), bytes.end(), m_keydata.begin()); } +bool XOnlyPubKey::IsFullyValid() const +{ + secp256k1_xonly_pubkey pubkey; + return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data()); +} + bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const { assert(sigbytes.size() == 64); @@ -188,13 +194,45 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), &pubkey); } -bool XOnlyPubKey::CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const +static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak"); + +uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const +{ + if (merkle_root == nullptr) { + // We have no scripts. The actual tweak does not matter, but follow BIP341 here to + // allow for reproducible tweaking. + return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256(); + } else { + return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256(); + } +} + +bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const +{ + secp256k1_xonly_pubkey internal_key; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false; + uint256 tweak = internal.ComputeTapTweakHash(&merkle_root); + return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin()); +} + +std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const { secp256k1_xonly_pubkey base_point; - if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, base.data())) return false; - return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &base_point, hash.begin()); + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt; + secp256k1_pubkey out; + uint256 tweak = ComputeTapTweakHash(merkle_root); + if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt; + int parity = -1; + std::pair<XOnlyPubKey, bool> ret; + secp256k1_xonly_pubkey out_xonly; + if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt; + secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly); + assert(parity == 0 || parity == 1); + ret.second = parity; + return ret; } + bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const { if (!IsValid()) return false; diff --git a/src/pubkey.h b/src/pubkey.h index 1af1187006..152a48dd18 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -13,6 +13,7 @@ #include <uint256.h> #include <cstring> +#include <optional> #include <vector> const unsigned int BIP32_EXTKEY_SIZE = 74; @@ -222,19 +223,56 @@ private: uint256 m_keydata; public: + /** Construct an empty x-only pubkey. */ + XOnlyPubKey() = default; + + XOnlyPubKey(const XOnlyPubKey&) = default; + XOnlyPubKey& operator=(const XOnlyPubKey&) = default; + + /** Determine if this pubkey is fully valid. This is true for approximately 50% of all + * possible 32-byte arrays. If false, VerifySchnorr and CreatePayToContract will always + * fail. */ + bool IsFullyValid() const; + /** Construct an x-only pubkey from exactly 32 bytes. */ explicit XOnlyPubKey(Span<const unsigned char> bytes); + /** Construct an x-only pubkey from a normal pubkey. */ + explicit XOnlyPubKey(const CPubKey& pubkey) : XOnlyPubKey(Span<const unsigned char>(pubkey.begin() + 1, pubkey.begin() + 33)) {} + /** Verify a Schnorr signature against this public key. * * sigbytes must be exactly 64 bytes. */ bool VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const; - bool CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const; + + /** Compute the Taproot tweak as specified in BIP341, with *this as internal + * key: + * - if merkle_root == nullptr: H_TapTweak(xonly_pubkey) + * - otherwise: H_TapTweak(xonly_pubkey || *merkle_root) + * + * Note that the behavior of this function with merkle_root != nullptr is + * consensus critical. + */ + uint256 ComputeTapTweakHash(const uint256* merkle_root) const; + + /** Verify that this is a Taproot tweaked output point, against a specified internal key, + * Merkle root, and parity. */ + bool CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const; + + /** Construct a Taproot tweaked output point with this point as internal key. */ + std::optional<std::pair<XOnlyPubKey, bool>> CreateTapTweak(const uint256* merkle_root) const; const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); } const unsigned char* data() const { return m_keydata.begin(); } - size_t size() const { return m_keydata.size(); } + static constexpr size_t size() { return decltype(m_keydata)::size(); } + const unsigned char* begin() const { return m_keydata.begin(); } + const unsigned char* end() const { return m_keydata.end(); } + unsigned char* begin() { return m_keydata.begin(); } + unsigned char* end() { return m_keydata.end(); } + bool operator==(const XOnlyPubKey& other) const { return m_keydata == other.m_keydata; } + bool operator!=(const XOnlyPubKey& other) const { return m_keydata != other.m_keydata; } + bool operator<(const XOnlyPubKey& other) const { return m_keydata < other.m_keydata; } }; struct CExtPubKey { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 69948402d0..9e6cf56d31 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -60,6 +60,7 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_WINDOWS) Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin); #elif defined(QT_QPA_PLATFORM_COCOA) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); Q_IMPORT_PLUGIN(QMacStylePlugin); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index eaacacb053..50f6e739e8 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -43,6 +43,7 @@ #include <QAction> #include <QApplication> #include <QComboBox> +#include <QCursor> #include <QDateTime> #include <QDragEnterEvent> #include <QListWidget> @@ -204,9 +205,6 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty // Subscribe to notifications from core subscribeToCoreSignals(); - connect(connectionsControl, &GUIUtil::ClickableLabel::clicked, [this] { - m_node.setNetworkActive(!m_node.getNetworkActive()); - }); connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked, [this] { openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK); }); @@ -591,7 +589,10 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH createTrayIconMenu(); // Keep up to date with client - updateNetworkState(); + setNetworkActive(m_node.getNetworkActive()); + connect(connectionsControl, &GUIUtil::ClickableLabel::clicked, [this] { + GUIUtil::PopupMenu(m_network_context_menu, QCursor::pos()); + }); connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections); connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive); @@ -935,14 +936,18 @@ void BitcoinGUI::updateNetworkState() QString tooltip; if (m_node.getNetworkActive()) { - tooltip = tr("%n active connection(s) to Bitcoin network", "", count) + QString(".<br>") + tr("Click to disable network activity."); + //: A substring of the tooltip. + tooltip = tr("%n active connection(s) to Bitcoin network.", "", count); } else { - tooltip = tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again."); + //: A substring of the tooltip. + tooltip = tr("Network activity disabled."); icon = ":/icons/network_disabled"; } // Don't word-wrap this (fixed-width) tooltip - tooltip = QString("<nobr>") + tooltip + QString("</nobr>"); + tooltip = QLatin1String("<nobr>") + tooltip + QLatin1String("<br>") + + //: A substring of the tooltip. "More actions" are available via the context menu. + tr("Click for more actions.") + QLatin1String("</nobr>"); connectionsControl->setToolTip(tooltip); connectionsControl->setThemedPixmap(icon, STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE); @@ -953,9 +958,24 @@ void BitcoinGUI::setNumConnections(int count) updateNetworkState(); } -void BitcoinGUI::setNetworkActive(bool networkActive) +void BitcoinGUI::setNetworkActive(bool network_active) { updateNetworkState(); + m_network_context_menu->clear(); + m_network_context_menu->addAction( + //: A context menu item. The "Peers tab" is an element of the "Node window". + tr("Show Peers tab"), + [this] { + rpcConsole->setTabFocus(RPCConsole::TabTypes::PEERS); + showDebugWindow(); + }); + m_network_context_menu->addAction( + network_active ? + //: A context menu item. + tr("Disable network activity") : + //: A context menu item. The network activity was disabled previously. + tr("Enable network activity"), + [this, new_state = !network_active] { m_node.setNetworkActive(new_state); }); } void BitcoinGUI::updateHeadersSyncProgressLabel() @@ -1405,7 +1425,6 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress) progressDialog = new QProgressDialog(title, QString(), 0, 100); GUIUtil::PolishProgressDialog(progressDialog); progressDialog->setWindowModality(Qt::ApplicationModal); - progressDialog->setMinimumDuration(0); progressDialog->setAutoClose(false); progressDialog->setValue(0); } else if (nProgress == 100) { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 65c5331d32..c83cd446a0 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -17,6 +17,7 @@ #include <QLabel> #include <QMainWindow> #include <QMap> +#include <QMenu> #include <QPoint> #include <QSystemTrayIcon> @@ -51,7 +52,6 @@ QT_BEGIN_NAMESPACE class QAction; class QComboBox; class QDateTime; -class QMenu; class QProgressBar; class QProgressDialog; QT_END_NAMESPACE @@ -175,6 +175,8 @@ private: HelpMessageDialog* helpMessageDialog = nullptr; ModalOverlay* modalOverlay = nullptr; + QMenu* m_network_context_menu = new QMenu(this); + #ifdef Q_OS_MAC CAppNapInhibitor* m_app_nap_inhibitor = nullptr; #endif @@ -222,7 +224,7 @@ public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set network state shown in the UI */ - void setNetworkActive(bool networkActive); + void setNetworkActive(bool network_active); /** Set number of blocks and last block date shown in the UI */ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state); diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 7a25ba907e..15e0d3fad9 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -470,13 +470,7 @@ </spacer> </item> <item> - <widget class="QPushButton" name="fontSmallerButton"> - <property name="maximumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> + <widget class="QToolButton" name="fontSmallerButton"> <property name="toolTip"> <string>Decrease font size</string> </property> @@ -489,26 +483,14 @@ </property> <property name="iconSize"> <size> - <width>24</width> - <height>16</height> + <width>22</width> + <height>22</height> </size> </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> </widget> </item> <item> - <widget class="QPushButton" name="fontBiggerButton"> - <property name="maximumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> + <widget class="QToolButton" name="fontBiggerButton"> <property name="toolTip"> <string>Increase font size</string> </property> @@ -521,26 +503,14 @@ </property> <property name="iconSize"> <size> - <width>24</width> - <height>16</height> + <width>22</width> + <height>22</height> </size> </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> </widget> </item> <item> - <widget class="QPushButton" name="clearButton"> - <property name="maximumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> + <widget class="QToolButton" name="clearButton"> <property name="toolTip"> <string>Clear console</string> </property> @@ -554,15 +524,15 @@ <iconset resource="../bitcoin.qrc"> <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset> </property> + <property name="iconSize"> + <size> + <width>22</width> + <height>22</height> + </size> + </property> <property name="shortcut"> <string notr="true">Ctrl+L</string> </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> </widget> </item> </layout> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 5ff40ae924..393dca8ccd 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -853,10 +853,12 @@ void PolishProgressDialog(QProgressDialog* dialog) // Workaround for macOS-only Qt bug; see: QTBUG-65750, QTBUG-70357. const int margin = TextWidth(dialog->fontMetrics(), ("X")); dialog->resize(dialog->width() + 2 * margin, dialog->height()); - dialog->show(); -#else - Q_UNUSED(dialog); #endif + // QProgressDialog estimates the time the operation will take (based on time + // for steps), and only shows itself if that estimate is beyond minimumDuration. + // The default minimumDuration value is 4 seconds, and it could make users + // think that the GUI is frozen. + dialog->setMinimumDuration(0); } int TextWidth(const QFontMetrics& fm, const QString& text) diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 13a4e3fd79..b146489ba8 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -340,7 +340,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+247"/> + <location filename="../bitcoingui.cpp" line="+245"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -405,27 +405,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+351"/> - <source>Click to disable network activity.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> + <location line="+358"/> <source>Network activity disabled.</source> + <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+0"/> - <source>Click to enable network activity again.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+399"/> + <location line="+426"/> <source>Proxy is <b>enabled</b>: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1064"/> + <location line="-1096"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -555,7 +546,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Tabs toolbar</translation> </message> <message> - <location line="+400"/> + <location line="+422"/> <source>Syncing Headers (%1%)…</source> <translation type="unfinished"></translation> </message> @@ -585,7 +576,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-744"/> + <location line="-766"/> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished"></translation> </message> @@ -605,15 +596,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+555"/> - <source>%n active connection(s) to Bitcoin network</source> - <translation> - <numerusform>%n active connection to Bitcoin network</numerusform> - <numerusform>%n active connections to Bitcoin network</numerusform> - </translation> - </message> - <message numerus="yes"> - <location line="+101"/> + <location line="+678"/> <source>Processed %n block(s) of transaction history.</source> <translation> <numerusform>Processed %n block of transaction history.</numerusform> @@ -661,7 +644,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Up to date</translation> </message> <message> - <location line="-693"/> + <location line="-715"/> <source>Load Partially Signed Bitcoin Transaction</source> <translation type="unfinished"></translation> </message> @@ -761,12 +744,45 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+245"/> + <location line="+248"/> <source>%1 client</source> <translation type="unfinished"></translation> </message> + <message numerus="yes"> + <location line="+158"/> + <source>%n active connection(s) to Bitcoin network.</source> + <extracomment>A substring of the tooltip.</extracomment> + <translation type="unfinished"> + <numerusform></numerusform> + <numerusform></numerusform> + </translation> + </message> <message> - <location line="+333"/> + <location line="+10"/> + <source>Click for more actions.</source> + <extracomment>A substring of the tooltip. "More actions" are available via the context menu.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>Show Peers tab</source> + <extracomment>A context menu item. The "Peers tab" is an element of the "Node window".</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Disable network activity</source> + <extracomment>A context menu item.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Enable network activity</source> + <extracomment>A context menu item. The network activity was disabled previously.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+157"/> <source>Error: %1</source> <translation type="unfinished"></translation> </message> @@ -776,7 +792,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+100"/> + <location line="+110"/> <source>Date: %1 </source> <translation type="unfinished"></translation> @@ -847,7 +863,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location line="+121"/> + <location line="+120"/> <source>Original message:</source> <translation type="unfinished"></translation> </message> @@ -1026,7 +1042,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+38"/> + <location line="+47"/> <location line="+54"/> <source>(no label)</source> <translation type="unfinished"></translation> @@ -1045,7 +1061,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>CreateWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="+250"/> + <location filename="../walletcontroller.cpp" line="+253"/> <source>Creating Wallet <b>%1</b>…</source> <translation type="unfinished"></translation> </message> @@ -1946,7 +1962,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../overviewpage.cpp" line="+191"/> + <location filename="../overviewpage.cpp" line="+193"/> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> <translation type="unfinished"></translation> </message> @@ -2208,7 +2224,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+118"/> + <location filename="../guiutil.cpp" line="+120"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> @@ -2474,7 +2490,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <location line="+23"/> <location line="+23"/> <location line="+26"/> - <location filename="../rpcconsole.h" line="+137"/> + <location filename="../rpcconsole.h" line="+138"/> <source>N/A</source> <translation>N/A</translation> </message> @@ -2593,7 +2609,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <location line="+68"/> - <location filename="../rpcconsole.cpp" line="+1046"/> + <location filename="../rpcconsole.cpp" line="+1091"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> @@ -2789,7 +2805,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-181"/> + <location filename="../rpcconsole.cpp" line="-201"/> <source>In:</source> <translation type="unfinished"></translation> </message> @@ -2834,12 +2850,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+37"/> + <location line="+38"/> <source>Never</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-392"/> + <location filename="../rpcconsole.cpp" line="-417"/> <source>Inbound: initiated by peer</source> <translation type="unfinished"></translation> </message> @@ -2908,42 +2924,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+311"/> - <source>Welcome to the %1 RPC console.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> - <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>Use %1 and %2 to increase or decrease the font size.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+4"/> - <source>Type %1 for an overview of available commands.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> - <source>For more information on using this console type %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> - <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+36"/> + <location line="+385"/> <source>Network activity disabled</source> <translation type="unfinished"></translation> </message> <message> - <location line="+66"/> + <location line="+77"/> <source>Executing command without any wallet</source> <translation type="unfinished"></translation> </message> @@ -2953,7 +2939,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-283"/> + <location line="-319"/> <source>Disconnect</source> <translation type="unfinished"></translation> </message> @@ -2983,7 +2969,25 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+379"/> + <location line="+150"/> + <source>Welcome to the %1 RPC console. +Use up and down arrows to navigate history, and %2 to clear screen. +Use %3 and %4 to increase or decrease the font size. +Type %5 for an overview of available commands. +For more information on using this console, type %6. + +%7WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.%8</source> + <extracomment>RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+156"/> + <source>Executing…</source> + <extracomment>A console message indicating an entered command is currently being executed.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+118"/> <source>(peer: %1)</source> <translation type="unfinished"></translation> </message> @@ -2993,7 +2997,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.h" line="-37"/> + <location filename="../rpcconsole.h" line="-38"/> <source>Unknown</source> <translation type="unfinished"></translation> </message> @@ -4485,7 +4489,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+262"/> + <location line="+276"/> <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> @@ -4564,7 +4568,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>UnitDisplayStatusBarControl</name> <message> - <location filename="../bitcoingui.cpp" line="+40"/> + <location filename="../bitcoingui.cpp" line="+41"/> <source>Unit to show amounts in. Click to select another unit.</source> <translation type="unfinished"></translation> </message> @@ -4572,7 +4576,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>WalletController</name> <message> - <location filename="../walletcontroller.cpp" line="-247"/> + <location filename="../walletcontroller.cpp" line="-250"/> <source>Close wallet</source> <translation type="unfinished"></translation> </message> diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf index 0f755fc81b..ffe7812738 100644 --- a/src/qt/locale/bitcoin_en.xlf +++ b/src/qt/locale/bitcoin_en.xlf @@ -381,613 +381,629 @@ Signing is only possible with addresses of the type 'legacy'.</source> <trans-unit id="_msg68" approved="yes"> <source xml:space="preserve">&Overview</source> <target xml:space="preserve">&Overview</target> - <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + <context-group purpose="location"><context context-type="linenumber">245</context></context-group> </trans-unit> <trans-unit id="_msg69" approved="yes"> <source xml:space="preserve">Show general overview of wallet</source> <target xml:space="preserve">Show general overview of wallet</target> - <context-group purpose="location"><context context-type="linenumber">248</context></context-group> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> <trans-unit id="_msg70" approved="yes"> <source xml:space="preserve">&Transactions</source> <target xml:space="preserve">&Transactions</target> - <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + <context-group purpose="location"><context context-type="linenumber">274</context></context-group> </trans-unit> <trans-unit id="_msg71" approved="yes"> <source xml:space="preserve">Browse transaction history</source> <target xml:space="preserve">Browse transaction history</target> - <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> <trans-unit id="_msg72" approved="yes"> <source xml:space="preserve">E&xit</source> <target xml:space="preserve">E&xit</target> - <context-group purpose="location"><context context-type="linenumber">300</context></context-group> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> <trans-unit id="_msg73" approved="yes"> <source xml:space="preserve">Quit application</source> <target xml:space="preserve">Quit application</target> - <context-group purpose="location"><context context-type="linenumber">301</context></context-group> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> </trans-unit> <trans-unit id="_msg74"> <source xml:space="preserve">&About %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">304</context></context-group> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> </trans-unit> <trans-unit id="_msg75"> <source xml:space="preserve">Show information about %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> <trans-unit id="_msg76" approved="yes"> <source xml:space="preserve">About &Qt</source> <target xml:space="preserve">About &Qt</target> - <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> <trans-unit id="_msg77" approved="yes"> <source xml:space="preserve">Show information about Qt</source> <target xml:space="preserve">Show information about Qt</target> - <context-group purpose="location"><context context-type="linenumber">309</context></context-group> + <context-group purpose="location"><context context-type="linenumber">307</context></context-group> </trans-unit> <trans-unit id="_msg78"> <source xml:space="preserve">Modify configuration options for %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">312</context></context-group> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> </trans-unit> <trans-unit id="_msg79"> <source xml:space="preserve">Create a new wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">358</context></context-group> + <context-group purpose="location"><context context-type="linenumber">356</context></context-group> </trans-unit> <trans-unit id="_msg80"> <source xml:space="preserve">Wallet:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">567</context></context-group> + <context-group purpose="location"><context context-type="linenumber">565</context></context-group> </trans-unit> <trans-unit id="_msg81"> - <source xml:space="preserve">Click to disable network activity.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">918</context></context-group> - </trans-unit> - <trans-unit id="_msg82"> <source xml:space="preserve">Network activity disabled.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">920</context></context-group> - </trans-unit> - <trans-unit id="_msg83"> - <source xml:space="preserve">Click to enable network activity again.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">920</context></context-group> + <context-group purpose="location"><context context-type="linenumber">923</context></context-group> + <note annotates="source" from="developer">A substring of the tooltip.</note> </trans-unit> - <trans-unit id="_msg84"> + <trans-unit id="_msg82"> <source xml:space="preserve">Proxy is <b>enabled</b>: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1319</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1349</context></context-group> </trans-unit> - <trans-unit id="_msg85" approved="yes"> + <trans-unit id="_msg83" approved="yes"> <source xml:space="preserve">Send coins to a Bitcoin address</source> <target xml:space="preserve">Send coins to a Bitcoin address</target> - <context-group purpose="location"><context context-type="linenumber">255</context></context-group> + <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg86" approved="yes"> + <trans-unit id="_msg84" approved="yes"> <source xml:space="preserve">Backup wallet to another location</source> <target xml:space="preserve">Backup wallet to another location</target> - <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> </trans-unit> - <trans-unit id="_msg87" approved="yes"> + <trans-unit id="_msg85" approved="yes"> <source xml:space="preserve">Change the passphrase used for wallet encryption</source> <target xml:space="preserve">Change the passphrase used for wallet encryption</target> - <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg88" approved="yes"> + <trans-unit id="_msg86" approved="yes"> <source xml:space="preserve">&Send</source> <target xml:space="preserve">&Send</target> - <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> </trans-unit> - <trans-unit id="_msg89" approved="yes"> + <trans-unit id="_msg87" approved="yes"> <source xml:space="preserve">&Receive</source> <target xml:space="preserve">&Receive</target> - <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> - <trans-unit id="_msg90"> + <trans-unit id="_msg88"> <source xml:space="preserve">&Options…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">311</context></context-group> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> </trans-unit> - <trans-unit id="_msg91" approved="yes"> + <trans-unit id="_msg89" approved="yes"> <source xml:space="preserve">&Show / Hide</source> <target xml:space="preserve">&Show / Hide</target> - <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + <context-group purpose="location"><context context-type="linenumber">313</context></context-group> </trans-unit> - <trans-unit id="_msg92" approved="yes"> + <trans-unit id="_msg90" approved="yes"> <source xml:space="preserve">Show or hide the main Window</source> <target xml:space="preserve">Show or hide the main Window</target> - <context-group purpose="location"><context context-type="linenumber">316</context></context-group> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> - <trans-unit id="_msg93"> + <trans-unit id="_msg91"> <source xml:space="preserve">&Encrypt Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + <context-group purpose="location"><context context-type="linenumber">316</context></context-group> </trans-unit> - <trans-unit id="_msg94" approved="yes"> + <trans-unit id="_msg92" approved="yes"> <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source> <target xml:space="preserve">Encrypt the private keys that belong to your wallet</target> - <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + <context-group purpose="location"><context context-type="linenumber">317</context></context-group> </trans-unit> - <trans-unit id="_msg95"> + <trans-unit id="_msg93"> <source xml:space="preserve">&Backup Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> - <trans-unit id="_msg96"> + <trans-unit id="_msg94"> <source xml:space="preserve">&Change Passphrase…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg97"> + <trans-unit id="_msg95"> <source xml:space="preserve">Sign &message…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg98" approved="yes"> + <trans-unit id="_msg96" approved="yes"> <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source> <target xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</target> - <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg99"> + <trans-unit id="_msg97"> <source xml:space="preserve">&Verify message…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">327</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg100" approved="yes"> + <trans-unit id="_msg98" approved="yes"> <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source> <target xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</target> - <context-group purpose="location"><context context-type="linenumber">328</context></context-group> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg101"> + <trans-unit id="_msg99"> <source xml:space="preserve">&Load PSBT from file…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> </trans-unit> - <trans-unit id="_msg102"> + <trans-unit id="_msg100"> <source xml:space="preserve">Load PSBT from clipboard…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> </trans-unit> - <trans-unit id="_msg103"> + <trans-unit id="_msg101"> <source xml:space="preserve">Open &URI…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <context-group purpose="location"><context context-type="linenumber">343</context></context-group> </trans-unit> - <trans-unit id="_msg104"> + <trans-unit id="_msg102"> <source xml:space="preserve">Close Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">353</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg105"> + <trans-unit id="_msg103"> <source xml:space="preserve">Create Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">354</context></context-group> </trans-unit> - <trans-unit id="_msg106"> + <trans-unit id="_msg104"> <source xml:space="preserve">Close All Wallets…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">360</context></context-group> + <context-group purpose="location"><context context-type="linenumber">358</context></context-group> </trans-unit> - <trans-unit id="_msg107" approved="yes"> + <trans-unit id="_msg105" approved="yes"> <source xml:space="preserve">&File</source> <target xml:space="preserve">&File</target> - <context-group purpose="location"><context context-type="linenumber">457</context></context-group> + <context-group purpose="location"><context context-type="linenumber">455</context></context-group> </trans-unit> - <trans-unit id="_msg108" approved="yes"> + <trans-unit id="_msg106" approved="yes"> <source xml:space="preserve">&Settings</source> <target xml:space="preserve">&Settings</target> - <context-group purpose="location"><context context-type="linenumber">475</context></context-group> + <context-group purpose="location"><context context-type="linenumber">473</context></context-group> </trans-unit> - <trans-unit id="_msg109" approved="yes"> + <trans-unit id="_msg107" approved="yes"> <source xml:space="preserve">&Help</source> <target xml:space="preserve">&Help</target> - <context-group purpose="location"><context context-type="linenumber">536</context></context-group> + <context-group purpose="location"><context context-type="linenumber">534</context></context-group> </trans-unit> - <trans-unit id="_msg110" approved="yes"> + <trans-unit id="_msg108" approved="yes"> <source xml:space="preserve">Tabs toolbar</source> <target xml:space="preserve">Tabs toolbar</target> - <context-group purpose="location"><context context-type="linenumber">547</context></context-group> + <context-group purpose="location"><context context-type="linenumber">545</context></context-group> </trans-unit> - <trans-unit id="_msg111"> + <trans-unit id="_msg109"> <source xml:space="preserve">Syncing Headers (%1%)…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">947</context></context-group> + <context-group purpose="location"><context context-type="linenumber">967</context></context-group> </trans-unit> - <trans-unit id="_msg112"> + <trans-unit id="_msg110"> <source xml:space="preserve">Synchronizing with network…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">993</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1013</context></context-group> </trans-unit> - <trans-unit id="_msg113"> + <trans-unit id="_msg111"> <source xml:space="preserve">Indexing blocks on disk…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">998</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1018</context></context-group> </trans-unit> - <trans-unit id="_msg114"> + <trans-unit id="_msg112"> <source xml:space="preserve">Processing blocks on disk…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1000</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1020</context></context-group> </trans-unit> - <trans-unit id="_msg115"> + <trans-unit id="_msg113"> <source xml:space="preserve">Reindexing blocks on disk…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1004</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1024</context></context-group> </trans-unit> - <trans-unit id="_msg116"> + <trans-unit id="_msg114"> <source xml:space="preserve">Connecting to peers…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1010</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1030</context></context-group> </trans-unit> - <trans-unit id="_msg117"> + <trans-unit id="_msg115"> <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">266</context></context-group> + <context-group purpose="location"><context context-type="linenumber">264</context></context-group> </trans-unit> - <trans-unit id="_msg118"> + <trans-unit id="_msg116"> <source xml:space="preserve">Show the list of used sending addresses and labels</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + <context-group purpose="location"><context context-type="linenumber">339</context></context-group> </trans-unit> - <trans-unit id="_msg119"> + <trans-unit id="_msg117"> <source xml:space="preserve">Show the list of used receiving addresses and labels</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">343</context></context-group> + <context-group purpose="location"><context context-type="linenumber">341</context></context-group> </trans-unit> - <trans-unit id="_msg120"> + <trans-unit id="_msg118"> <source xml:space="preserve">&Command-line options</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">363</context></context-group> + <context-group purpose="location"><context context-type="linenumber">361</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">918</context></context-group> - <trans-unit id="_msg121[0]" approved="yes"> - <source xml:space="preserve">%n active connection(s) to Bitcoin network</source> - <target xml:space="preserve">%n active connection to Bitcoin network</target> - </trans-unit> - <trans-unit id="_msg121[1]" approved="yes"> - <source xml:space="preserve">%n active connection(s) to Bitcoin network</source> - <target xml:space="preserve">%n active connections to Bitcoin network</target> - </trans-unit> - </group> - <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">1019</context></context-group> - <trans-unit id="_msg122[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">1039</context></context-group> + <trans-unit id="_msg119[0]" approved="yes"> <source xml:space="preserve">Processed %n block(s) of transaction history.</source> <target xml:space="preserve">Processed %n block of transaction history.</target> </trans-unit> - <trans-unit id="_msg122[1]" approved="yes"> + <trans-unit id="_msg119[1]" approved="yes"> <source xml:space="preserve">Processed %n block(s) of transaction history.</source> <target xml:space="preserve">Processed %n blocks of transaction history.</target> </trans-unit> </group> - <trans-unit id="_msg123" approved="yes"> + <trans-unit id="_msg120" approved="yes"> <source xml:space="preserve">%1 behind</source> <target xml:space="preserve">%1 behind</target> - <context-group purpose="location"><context context-type="linenumber">1042</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1062</context></context-group> </trans-unit> - <trans-unit id="_msg124"> + <trans-unit id="_msg121"> <source xml:space="preserve">Catching up…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1047</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1067</context></context-group> </trans-unit> - <trans-unit id="_msg125" approved="yes"> + <trans-unit id="_msg122" approved="yes"> <source xml:space="preserve">Last received block was generated %1 ago.</source> <target xml:space="preserve">Last received block was generated %1 ago.</target> - <context-group purpose="location"><context context-type="linenumber">1066</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1086</context></context-group> </trans-unit> - <trans-unit id="_msg126" approved="yes"> + <trans-unit id="_msg123" approved="yes"> <source xml:space="preserve">Transactions after this will not yet be visible.</source> <target xml:space="preserve">Transactions after this will not yet be visible.</target> - <context-group purpose="location"><context context-type="linenumber">1068</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1088</context></context-group> </trans-unit> - <trans-unit id="_msg127" approved="yes"> + <trans-unit id="_msg124" approved="yes"> <source xml:space="preserve">Error</source> <target xml:space="preserve">Error</target> - <context-group purpose="location"><context context-type="linenumber">1093</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1113</context></context-group> </trans-unit> - <trans-unit id="_msg128" approved="yes"> + <trans-unit id="_msg125" approved="yes"> <source xml:space="preserve">Warning</source> <target xml:space="preserve">Warning</target> - <context-group purpose="location"><context context-type="linenumber">1097</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1117</context></context-group> </trans-unit> - <trans-unit id="_msg129" approved="yes"> + <trans-unit id="_msg126" approved="yes"> <source xml:space="preserve">Information</source> <target xml:space="preserve">Information</target> - <context-group purpose="location"><context context-type="linenumber">1101</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1121</context></context-group> </trans-unit> - <trans-unit id="_msg130" approved="yes"> + <trans-unit id="_msg127" approved="yes"> <source xml:space="preserve">Up to date</source> <target xml:space="preserve">Up to date</target> - <context-group purpose="location"><context context-type="linenumber">1023</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1043</context></context-group> </trans-unit> - <trans-unit id="_msg131"> + <trans-unit id="_msg128"> <source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + <context-group purpose="location"><context context-type="linenumber">328</context></context-group> </trans-unit> - <trans-unit id="_msg132"> + <trans-unit id="_msg129"> <source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + <context-group purpose="location"><context context-type="linenumber">330</context></context-group> </trans-unit> - <trans-unit id="_msg133"> + <trans-unit id="_msg130"> <source xml:space="preserve">Node window</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> </trans-unit> - <trans-unit id="_msg134"> + <trans-unit id="_msg131"> <source xml:space="preserve">Open node debugging and diagnostic console</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> </trans-unit> - <trans-unit id="_msg135"> + <trans-unit id="_msg132"> <source xml:space="preserve">&Sending addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">340</context></context-group> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> </trans-unit> - <trans-unit id="_msg136"> + <trans-unit id="_msg133"> <source xml:space="preserve">&Receiving addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">342</context></context-group> + <context-group purpose="location"><context context-type="linenumber">340</context></context-group> </trans-unit> - <trans-unit id="_msg137"> + <trans-unit id="_msg134"> <source xml:space="preserve">Open a bitcoin: URI</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">346</context></context-group> + <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> - <trans-unit id="_msg138"> + <trans-unit id="_msg135"> <source xml:space="preserve">Open Wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">348</context></context-group> + <context-group purpose="location"><context context-type="linenumber">346</context></context-group> </trans-unit> - <trans-unit id="_msg139"> + <trans-unit id="_msg136"> <source xml:space="preserve">Open a wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + <context-group purpose="location"><context context-type="linenumber">348</context></context-group> </trans-unit> - <trans-unit id="_msg140"> + <trans-unit id="_msg137"> <source xml:space="preserve">Close wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> </trans-unit> - <trans-unit id="_msg141"> + <trans-unit id="_msg138"> <source xml:space="preserve">Close all wallets</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">359</context></context-group> </trans-unit> - <trans-unit id="_msg142"> + <trans-unit id="_msg139"> <source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + <context-group purpose="location"><context context-type="linenumber">363</context></context-group> </trans-unit> - <trans-unit id="_msg143"> + <trans-unit id="_msg140"> <source xml:space="preserve">&Mask values</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + <context-group purpose="location"><context context-type="linenumber">365</context></context-group> </trans-unit> - <trans-unit id="_msg144"> + <trans-unit id="_msg141"> <source xml:space="preserve">Mask the values in the Overview tab</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">369</context></context-group> + <context-group purpose="location"><context context-type="linenumber">367</context></context-group> </trans-unit> - <trans-unit id="_msg145"> + <trans-unit id="_msg142"> <source xml:space="preserve">default wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">401</context></context-group> + <context-group purpose="location"><context context-type="linenumber">399</context></context-group> </trans-unit> - <trans-unit id="_msg146"> + <trans-unit id="_msg143"> <source xml:space="preserve">No wallets available</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">422</context></context-group> + <context-group purpose="location"><context context-type="linenumber">420</context></context-group> </trans-unit> - <trans-unit id="_msg147"> + <trans-unit id="_msg144"> <source xml:space="preserve">&Window</source> <target xml:space="preserve" state="needs-review-translation">&Window</target> - <context-group purpose="location"><context context-type="linenumber">486</context></context-group> + <context-group purpose="location"><context context-type="linenumber">484</context></context-group> </trans-unit> - <trans-unit id="_msg148"> + <trans-unit id="_msg145"> <source xml:space="preserve">Minimize</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">488</context></context-group> + <context-group purpose="location"><context context-type="linenumber">486</context></context-group> </trans-unit> - <trans-unit id="_msg149"> + <trans-unit id="_msg146"> <source xml:space="preserve">Zoom</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">498</context></context-group> + <context-group purpose="location"><context context-type="linenumber">496</context></context-group> </trans-unit> - <trans-unit id="_msg150"> + <trans-unit id="_msg147"> <source xml:space="preserve">Main Window</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">516</context></context-group> + <context-group purpose="location"><context context-type="linenumber">514</context></context-group> </trans-unit> - <trans-unit id="_msg151"> + <trans-unit id="_msg148"> <source xml:space="preserve">%1 client</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">761</context></context-group> + <context-group purpose="location"><context context-type="linenumber">762</context></context-group> + </trans-unit> + <group restype="x-gettext-plurals"> + <context-group purpose="location"><context context-type="linenumber">920</context></context-group> + <note annotates="source" from="developer">A substring of the tooltip.</note> + <trans-unit id="_msg149[0]"> + <source xml:space="preserve">%n active connection(s) to Bitcoin network.</source> + <target xml:space="preserve"></target> + </trans-unit> + <trans-unit id="_msg149[1]"> + <source xml:space="preserve">%n active connection(s) to Bitcoin network.</source> + <target xml:space="preserve"></target> + </trans-unit> + </group> + <trans-unit id="_msg150"> + <source xml:space="preserve">Click for more actions.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">930</context></context-group> + <note annotates="source" from="developer">A substring of the tooltip. "More actions" are available via the context menu.</note> + </trans-unit> + <trans-unit id="_msg151"> + <source xml:space="preserve">Show Peers tab</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">947</context></context-group> + <note annotates="source" from="developer">A context menu item. The "Peers tab" is an element of the "Node window".</note> </trans-unit> <trans-unit id="_msg152"> - <source xml:space="preserve">Error: %1</source> + <source xml:space="preserve">Disable network activity</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1094</context></context-group> + <context-group purpose="location"><context context-type="linenumber">955</context></context-group> + <note annotates="source" from="developer">A context menu item.</note> </trans-unit> <trans-unit id="_msg153"> - <source xml:space="preserve">Warning: %1</source> + <source xml:space="preserve">Enable network activity</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1098</context></context-group> + <context-group purpose="location"><context context-type="linenumber">957</context></context-group> + <note annotates="source" from="developer">A context menu item. The network activity was disabled previously.</note> </trans-unit> <trans-unit id="_msg154"> + <source xml:space="preserve">Error: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1114</context></context-group> + </trans-unit> + <trans-unit id="_msg155"> + <source xml:space="preserve">Warning: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1118</context></context-group> + </trans-unit> + <trans-unit id="_msg156"> <source xml:space="preserve">Date: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1198</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1228</context></context-group> </trans-unit> - <trans-unit id="_msg155"> + <trans-unit id="_msg157"> <source xml:space="preserve">Amount: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1199</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1229</context></context-group> </trans-unit> - <trans-unit id="_msg156"> + <trans-unit id="_msg158"> <source xml:space="preserve">Wallet: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1201</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1231</context></context-group> </trans-unit> - <trans-unit id="_msg157"> + <trans-unit id="_msg159"> <source xml:space="preserve">Type: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1203</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1233</context></context-group> </trans-unit> - <trans-unit id="_msg158"> + <trans-unit id="_msg160"> <source xml:space="preserve">Label: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1205</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1235</context></context-group> </trans-unit> - <trans-unit id="_msg159"> + <trans-unit id="_msg161"> <source xml:space="preserve">Address: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1207</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1237</context></context-group> </trans-unit> - <trans-unit id="_msg160" approved="yes"> + <trans-unit id="_msg162" approved="yes"> <source xml:space="preserve">Sent transaction</source> <target xml:space="preserve">Sent transaction</target> - <context-group purpose="location"><context context-type="linenumber">1208</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1238</context></context-group> </trans-unit> - <trans-unit id="_msg161" approved="yes"> + <trans-unit id="_msg163" approved="yes"> <source xml:space="preserve">Incoming transaction</source> <target xml:space="preserve">Incoming transaction</target> - <context-group purpose="location"><context context-type="linenumber">1208</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1238</context></context-group> </trans-unit> - <trans-unit id="_msg162"> + <trans-unit id="_msg164"> <source xml:space="preserve">HD key generation is <b>enabled</b></source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1260</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1290</context></context-group> </trans-unit> - <trans-unit id="_msg163"> + <trans-unit id="_msg165"> <source xml:space="preserve">HD key generation is <b>disabled</b></source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1260</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1290</context></context-group> </trans-unit> - <trans-unit id="_msg164"> + <trans-unit id="_msg166"> <source xml:space="preserve">Private key <b>disabled</b></source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1260</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1290</context></context-group> </trans-unit> - <trans-unit id="_msg165" approved="yes"> + <trans-unit id="_msg167" approved="yes"> <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <target xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></target> - <context-group purpose="location"><context context-type="linenumber">1279</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1309</context></context-group> </trans-unit> - <trans-unit id="_msg166" approved="yes"> + <trans-unit id="_msg168" approved="yes"> <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></source> <target xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></target> - <context-group purpose="location"><context context-type="linenumber">1287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1317</context></context-group> </trans-unit> - <trans-unit id="_msg167"> + <trans-unit id="_msg169"> <source xml:space="preserve">Original message:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1408</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1437</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl"> - <trans-unit id="_msg168"> + <trans-unit id="_msg170"> <source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1448</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1478</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> - <trans-unit id="_msg169"> + <trans-unit id="_msg171"> <source xml:space="preserve">Coin Selection</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg170"> + <trans-unit id="_msg172"> <source xml:space="preserve">Quantity:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">48</context></context-group> </trans-unit> - <trans-unit id="_msg171"> + <trans-unit id="_msg173"> <source xml:space="preserve">Bytes:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">77</context></context-group> </trans-unit> - <trans-unit id="_msg172"> + <trans-unit id="_msg174"> <source xml:space="preserve">Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg173"> + <trans-unit id="_msg175"> <source xml:space="preserve">Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">202</context></context-group> </trans-unit> - <trans-unit id="_msg174"> + <trans-unit id="_msg176"> <source xml:space="preserve">Dust:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">154</context></context-group> </trans-unit> - <trans-unit id="_msg175"> + <trans-unit id="_msg177"> <source xml:space="preserve">After Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">247</context></context-group> </trans-unit> - <trans-unit id="_msg176"> + <trans-unit id="_msg178"> <source xml:space="preserve">Change:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> - <trans-unit id="_msg177"> + <trans-unit id="_msg179"> <source xml:space="preserve">(un)select all</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg178"> + <trans-unit id="_msg180"> <source xml:space="preserve">Tree mode</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg179"> + <trans-unit id="_msg181"> <source xml:space="preserve">List mode</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">364</context></context-group> </trans-unit> - <trans-unit id="_msg180"> + <trans-unit id="_msg182"> <source xml:space="preserve">Amount</source> <target xml:space="preserve" state="needs-review-translation">Amount</target> <context-group purpose="location"><context context-type="linenumber">420</context></context-group> </trans-unit> - <trans-unit id="_msg181"> + <trans-unit id="_msg183"> <source xml:space="preserve">Received with label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">425</context></context-group> </trans-unit> - <trans-unit id="_msg182"> + <trans-unit id="_msg184"> <source xml:space="preserve">Received with address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">430</context></context-group> </trans-unit> - <trans-unit id="_msg183"> + <trans-unit id="_msg185"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">435</context></context-group> </trans-unit> - <trans-unit id="_msg184"> + <trans-unit id="_msg186"> <source xml:space="preserve">Confirmations</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">440</context></context-group> </trans-unit> - <trans-unit id="_msg185"> + <trans-unit id="_msg187"> <source xml:space="preserve">Confirmed</source> <target xml:space="preserve" state="needs-review-translation">Confirmed</target> <context-group purpose="location"><context context-type="linenumber">443</context></context-group> @@ -996,172 +1012,172 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../coincontroldialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> - <trans-unit id="_msg186"> + <trans-unit id="_msg188"> <source xml:space="preserve">Copy address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">55</context></context-group> </trans-unit> - <trans-unit id="_msg187"> + <trans-unit id="_msg189"> <source xml:space="preserve">Copy label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">56</context></context-group> </trans-unit> - <trans-unit id="_msg188"> + <trans-unit id="_msg190"> <source xml:space="preserve">Copy amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">57</context></context-group> <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg189"> + <trans-unit id="_msg191"> <source xml:space="preserve">Copy transaction ID</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg190"> + <trans-unit id="_msg192"> <source xml:space="preserve">Lock unspent</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">60</context></context-group> </trans-unit> - <trans-unit id="_msg191"> + <trans-unit id="_msg193"> <source xml:space="preserve">Unlock unspent</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">61</context></context-group> </trans-unit> - <trans-unit id="_msg192"> + <trans-unit id="_msg194"> <source xml:space="preserve">Copy quantity</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> - <trans-unit id="_msg193"> + <trans-unit id="_msg195"> <source xml:space="preserve">Copy fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">67</context></context-group> </trans-unit> - <trans-unit id="_msg194"> + <trans-unit id="_msg196"> <source xml:space="preserve">Copy after fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">68</context></context-group> </trans-unit> - <trans-unit id="_msg195"> + <trans-unit id="_msg197"> <source xml:space="preserve">Copy bytes</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">69</context></context-group> </trans-unit> - <trans-unit id="_msg196"> + <trans-unit id="_msg198"> <source xml:space="preserve">Copy dust</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">70</context></context-group> </trans-unit> - <trans-unit id="_msg197"> + <trans-unit id="_msg199"> <source xml:space="preserve">Copy change</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg198"> + <trans-unit id="_msg200"> <source xml:space="preserve">(%1 locked)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> - <trans-unit id="_msg199"> + <trans-unit id="_msg201"> <source xml:space="preserve">yes</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">528</context></context-group> </trans-unit> - <trans-unit id="_msg200"> + <trans-unit id="_msg202"> <source xml:space="preserve">no</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">528</context></context-group> </trans-unit> - <trans-unit id="_msg201"> + <trans-unit id="_msg203"> <source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">542</context></context-group> </trans-unit> - <trans-unit id="_msg202"> + <trans-unit id="_msg204"> <source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">547</context></context-group> </trans-unit> - <trans-unit id="_msg203"> + <trans-unit id="_msg205"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">585</context></context-group> - <context-group purpose="location"><context context-type="linenumber">639</context></context-group> + <context-group purpose="location"><context context-type="linenumber">594</context></context-group> + <context-group purpose="location"><context context-type="linenumber">648</context></context-group> </trans-unit> - <trans-unit id="_msg204"> + <trans-unit id="_msg206"> <source xml:space="preserve">change from %1 (%2)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">632</context></context-group> + <context-group purpose="location"><context context-type="linenumber">641</context></context-group> </trans-unit> - <trans-unit id="_msg205"> + <trans-unit id="_msg207"> <source xml:space="preserve">(change)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">633</context></context-group> + <context-group purpose="location"><context context-type="linenumber">642</context></context-group> </trans-unit> </group> </body></file> <file original="../walletcontroller.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletActivity"> - <trans-unit id="_msg206"> + <trans-unit id="_msg208"> <source xml:space="preserve">Creating Wallet <b>%1</b>…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg207"> + <trans-unit id="_msg209"> <source xml:space="preserve">Create wallet failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">278</context></context-group> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> </trans-unit> - <trans-unit id="_msg208"> + <trans-unit id="_msg210"> <source xml:space="preserve">Create wallet warning</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">280</context></context-group> + <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="OpenWalletActivity"> - <trans-unit id="_msg209"> + <trans-unit id="_msg211"> <source xml:space="preserve">Open wallet failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg210"> + <trans-unit id="_msg212"> <source xml:space="preserve">Open wallet warning</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg211"> + <trans-unit id="_msg213"> <source xml:space="preserve">default wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> </trans-unit> - <trans-unit id="_msg212"> + <trans-unit id="_msg214"> <source xml:space="preserve">Opening Wallet <b>%1</b>…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + <context-group purpose="location"><context context-type="linenumber">336</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="WalletController"> - <trans-unit id="_msg213"> + <trans-unit id="_msg215"> <source xml:space="preserve">Close wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> - <trans-unit id="_msg214"> + <trans-unit id="_msg216"> <source xml:space="preserve">Are you sure you wish to close the wallet <i>%1</i>?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> - <trans-unit id="_msg215"> + <trans-unit id="_msg217"> <source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg216"> + <trans-unit id="_msg218"> <source xml:space="preserve">Close all wallets</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">101</context></context-group> </trans-unit> - <trans-unit id="_msg217"> + <trans-unit id="_msg219"> <source xml:space="preserve">Are you sure you wish to close all wallets?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">102</context></context-group> @@ -1170,62 +1186,62 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> - <trans-unit id="_msg218"> + <trans-unit id="_msg220"> <source xml:space="preserve">Create Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg219"> + <trans-unit id="_msg221"> <source xml:space="preserve">Wallet Name</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">25</context></context-group> </trans-unit> - <trans-unit id="_msg220"> + <trans-unit id="_msg222"> <source xml:space="preserve">Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">38</context></context-group> </trans-unit> - <trans-unit id="_msg221"> + <trans-unit id="_msg223"> <source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg222"> + <trans-unit id="_msg224"> <source xml:space="preserve">Encrypt Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg223"> + <trans-unit id="_msg225"> <source xml:space="preserve">Advanced Options</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg224"> + <trans-unit id="_msg226"> <source xml:space="preserve">Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> - <trans-unit id="_msg225"> + <trans-unit id="_msg227"> <source xml:space="preserve">Disable Private Keys</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg226"> + <trans-unit id="_msg228"> <source xml:space="preserve">Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg227"> + <trans-unit id="_msg229"> <source xml:space="preserve">Make Blank Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg228"> + <trans-unit id="_msg230"> <source xml:space="preserve">Use descriptors for scriptPubKey management</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">105</context></context-group> </trans-unit> - <trans-unit id="_msg229"> + <trans-unit id="_msg231"> <source xml:space="preserve">Descriptor Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">108</context></context-group> @@ -1234,12 +1250,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../createwalletdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> - <trans-unit id="_msg230"> + <trans-unit id="_msg232"> <source xml:space="preserve">Create</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">21</context></context-group> </trans-unit> - <trans-unit id="_msg231"> + <trans-unit id="_msg233"> <source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">63</context></context-group> @@ -1248,27 +1264,27 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="EditAddressDialog"> - <trans-unit id="_msg232" approved="yes"> + <trans-unit id="_msg234" approved="yes"> <source xml:space="preserve">Edit Address</source> <target xml:space="preserve">Edit Address</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg233" approved="yes"> + <trans-unit id="_msg235" approved="yes"> <source xml:space="preserve">&Label</source> <target xml:space="preserve">&Label</target> <context-group purpose="location"><context context-type="linenumber">25</context></context-group> </trans-unit> - <trans-unit id="_msg234"> + <trans-unit id="_msg236"> <source xml:space="preserve">The label associated with this address list entry</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">35</context></context-group> </trans-unit> - <trans-unit id="_msg235"> + <trans-unit id="_msg237"> <source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">52</context></context-group> </trans-unit> - <trans-unit id="_msg236" approved="yes"> + <trans-unit id="_msg238" approved="yes"> <source xml:space="preserve">&Address</source> <target xml:space="preserve">&Address</target> <context-group purpose="location"><context context-type="linenumber">42</context></context-group> @@ -1277,42 +1293,42 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../editaddressdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="EditAddressDialog"> - <trans-unit id="_msg237"> + <trans-unit id="_msg239"> <source xml:space="preserve">New sending address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">29</context></context-group> </trans-unit> - <trans-unit id="_msg238"> + <trans-unit id="_msg240"> <source xml:space="preserve">Edit receiving address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">32</context></context-group> </trans-unit> - <trans-unit id="_msg239"> + <trans-unit id="_msg241"> <source xml:space="preserve">Edit sending address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">36</context></context-group> </trans-unit> - <trans-unit id="_msg240"> + <trans-unit id="_msg242"> <source xml:space="preserve">The entered address "%1" is not a valid Bitcoin address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">113</context></context-group> </trans-unit> - <trans-unit id="_msg241"> + <trans-unit id="_msg243"> <source xml:space="preserve">Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg242"> + <trans-unit id="_msg244"> <source xml:space="preserve">The entered address "%1" is already in the address book with label "%2".</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">151</context></context-group> </trans-unit> - <trans-unit id="_msg243"> + <trans-unit id="_msg245"> <source xml:space="preserve">Could not unlock wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">123</context></context-group> </trans-unit> - <trans-unit id="_msg244"> + <trans-unit id="_msg246"> <source xml:space="preserve">New key generation failed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">128</context></context-group> @@ -1321,59 +1337,59 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../intro.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="FreespaceChecker"> - <trans-unit id="_msg245" approved="yes"> + <trans-unit id="_msg247" approved="yes"> <source xml:space="preserve">A new data directory will be created.</source> <target xml:space="preserve">A new data directory will be created.</target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg246" approved="yes"> + <trans-unit id="_msg248" approved="yes"> <source xml:space="preserve">name</source> <target xml:space="preserve">name</target> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg247" approved="yes"> + <trans-unit id="_msg249" approved="yes"> <source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source> <target xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</target> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg248" approved="yes"> + <trans-unit id="_msg250" approved="yes"> <source xml:space="preserve">Path already exists, and is not a directory.</source> <target xml:space="preserve">Path already exists, and is not a directory.</target> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg249" approved="yes"> + <trans-unit id="_msg251" approved="yes"> <source xml:space="preserve">Cannot create data directory here.</source> <target xml:space="preserve">Cannot create data directory here.</target> <context-group purpose="location"><context context-type="linenumber">107</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="Intro"> - <trans-unit id="_msg250"> + <trans-unit id="_msg252"> <source xml:space="preserve">Bitcoin</source> <target xml:space="preserve" state="needs-review-translation">Bitcoin</target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg251"> + <trans-unit id="_msg253"> <source xml:space="preserve">%1 GB of free space available</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg252"> + <trans-unit id="_msg254"> <source xml:space="preserve">(of %1 GB needed)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> - <trans-unit id="_msg253"> + <trans-unit id="_msg255"> <source xml:space="preserve">(%1 GB needed for full chain)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> - <trans-unit id="_msg254"> + <trans-unit id="_msg256"> <source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">378</context></context-group> </trans-unit> - <trans-unit id="_msg255"> + <trans-unit id="_msg257"> <source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">381</context></context-group> @@ -1381,31 +1397,31 @@ Signing is only possible with addresses of the type 'legacy'.</source> <group restype="x-gettext-plurals"> <context-group purpose="location"><context context-type="linenumber">390</context></context-group> <note annotates="source" from="developer">Explanatory text on the capability of the current prune target.</note> - <trans-unit id="_msg256[0]"> + <trans-unit id="_msg258[0]"> <source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source> <target xml:space="preserve"></target> </trans-unit> - <trans-unit id="_msg256[1]"> + <trans-unit id="_msg258[1]"> <source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source> <target xml:space="preserve"></target> </trans-unit> </group> - <trans-unit id="_msg257"> + <trans-unit id="_msg259"> <source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> - <trans-unit id="_msg258"> + <trans-unit id="_msg260"> <source xml:space="preserve">The wallet will also be stored in this directory.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">394</context></context-group> </trans-unit> - <trans-unit id="_msg259"> + <trans-unit id="_msg261"> <source xml:space="preserve">Error: Specified data directory "%1" cannot be created.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg260" approved="yes"> + <trans-unit id="_msg262" approved="yes"> <source xml:space="preserve">Error</source> <target xml:space="preserve">Error</target> <context-group purpose="location"><context context-type="linenumber">280</context></context-group> @@ -1414,29 +1430,29 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../utilitydialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="HelpMessageDialog"> - <trans-unit id="_msg261"> + <trans-unit id="_msg263"> <source xml:space="preserve">version</source> <target xml:space="preserve" state="needs-review-translation">version</target> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg262"> + <trans-unit id="_msg264"> <source xml:space="preserve">About %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">41</context></context-group> </trans-unit> - <trans-unit id="_msg263"> + <trans-unit id="_msg265"> <source xml:space="preserve">Command-line options</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">60</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="ShutdownWindow"> - <trans-unit id="_msg264"> + <trans-unit id="_msg266"> <source xml:space="preserve">%1 is shutting down…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> - <trans-unit id="_msg265"> + <trans-unit id="_msg267"> <source xml:space="preserve">Do not shut down the computer until this window disappears.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> @@ -1445,57 +1461,57 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="Intro"> - <trans-unit id="_msg266" approved="yes"> + <trans-unit id="_msg268" approved="yes"> <source xml:space="preserve">Welcome</source> <target xml:space="preserve">Welcome</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg267"> + <trans-unit id="_msg269"> <source xml:space="preserve">Welcome to %1.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">23</context></context-group> </trans-unit> - <trans-unit id="_msg268"> + <trans-unit id="_msg270"> <source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg269"> + <trans-unit id="_msg271"> <source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg270"> + <trans-unit id="_msg272"> <source xml:space="preserve">Limit block chain storage to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> - <trans-unit id="_msg271"> + <trans-unit id="_msg273"> <source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg272"> + <trans-unit id="_msg274"> <source xml:space="preserve"> GB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg273"> + <trans-unit id="_msg275"> <source xml:space="preserve">This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> - <trans-unit id="_msg274"> + <trans-unit id="_msg276"> <source xml:space="preserve">If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg275" approved="yes"> + <trans-unit id="_msg277" approved="yes"> <source xml:space="preserve">Use the default data directory</source> <target xml:space="preserve">Use the default data directory</target> <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg276" approved="yes"> + <trans-unit id="_msg278" approved="yes"> <source xml:space="preserve">Use a custom data directory:</source> <target xml:space="preserve">Use a custom data directory:</target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> @@ -1504,65 +1520,65 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> - <trans-unit id="_msg277"> + <trans-unit id="_msg279"> <source xml:space="preserve">Form</source> <target xml:space="preserve" state="needs-review-translation">Form</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg278"> + <trans-unit id="_msg280"> <source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">133</context></context-group> </trans-unit> - <trans-unit id="_msg279"> + <trans-unit id="_msg281"> <source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg280"> + <trans-unit id="_msg282"> <source xml:space="preserve">Number of blocks left</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg281"> + <trans-unit id="_msg283"> <source xml:space="preserve">Unknown…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">222</context></context-group> <context-group purpose="location"><context context-type="linenumber">248</context></context-group> <context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg282"> + <trans-unit id="_msg284"> <source xml:space="preserve">calculating…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">292</context></context-group> <context-group purpose="location"><context context-type="linenumber">312</context></context-group> </trans-unit> - <trans-unit id="_msg283"> + <trans-unit id="_msg285"> <source xml:space="preserve">Last block time</source> <target xml:space="preserve" state="needs-review-translation">Last block time</target> <context-group purpose="location"><context context-type="linenumber">235</context></context-group> </trans-unit> - <trans-unit id="_msg284"> + <trans-unit id="_msg286"> <source xml:space="preserve">Progress</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">261</context></context-group> </trans-unit> - <trans-unit id="_msg285"> + <trans-unit id="_msg287"> <source xml:space="preserve">Progress increase per hour</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> - <trans-unit id="_msg286"> + <trans-unit id="_msg288"> <source xml:space="preserve">Estimated time left until synced</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg287"> + <trans-unit id="_msg289"> <source xml:space="preserve">Hide</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">342</context></context-group> </trans-unit> - <trans-unit id="_msg288"> + <trans-unit id="_msg290"> <source xml:space="preserve">Esc</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">345</context></context-group> @@ -1571,19 +1587,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../modaloverlay.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> - <trans-unit id="_msg289"> + <trans-unit id="_msg291"> <source xml:space="preserve">%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg290"> + <trans-unit id="_msg292"> <source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">158</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="QObject"> - <trans-unit id="_msg291"> + <trans-unit id="_msg293"> <source xml:space="preserve">unknown</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">123</context></context-group> @@ -1592,12 +1608,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OpenURIDialog"> - <trans-unit id="_msg292"> + <trans-unit id="_msg294"> <source xml:space="preserve">Open bitcoin URI</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg293"> + <trans-unit id="_msg295"> <source xml:space="preserve">URI:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">22</context></context-group> @@ -1606,319 +1622,319 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> - <trans-unit id="_msg294" approved="yes"> + <trans-unit id="_msg296" approved="yes"> <source xml:space="preserve">Options</source> <target xml:space="preserve">Options</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg295" approved="yes"> + <trans-unit id="_msg297" approved="yes"> <source xml:space="preserve">&Main</source> <target xml:space="preserve">&Main</target> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg296"> + <trans-unit id="_msg298"> <source xml:space="preserve">Automatically start %1 after logging in to the system.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">33</context></context-group> </trans-unit> - <trans-unit id="_msg297"> + <trans-unit id="_msg299"> <source xml:space="preserve">&Start %1 on system login</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">36</context></context-group> </trans-unit> - <trans-unit id="_msg298"> + <trans-unit id="_msg300"> <source xml:space="preserve">Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg299"> + <trans-unit id="_msg301"> <source xml:space="preserve">Size of &database cache</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg300"> + <trans-unit id="_msg302"> <source xml:space="preserve">Number of script &verification threads</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">151</context></context-group> </trans-unit> - <trans-unit id="_msg301"> + <trans-unit id="_msg303"> <source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">322</context></context-group> <context-group purpose="location"><context context-type="linenumber">509</context></context-group> </trans-unit> - <trans-unit id="_msg302"> + <trans-unit id="_msg304"> <source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">391</context></context-group> <context-group purpose="location"><context context-type="linenumber">414</context></context-group> <context-group purpose="location"><context context-type="linenumber">437</context></context-group> </trans-unit> - <trans-unit id="_msg303"> + <trans-unit id="_msg305"> <source xml:space="preserve">Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">606</context></context-group> </trans-unit> - <trans-unit id="_msg304"> + <trans-unit id="_msg306"> <source xml:space="preserve">Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">686</context></context-group> <context-group purpose="location"><context context-type="linenumber">699</context></context-group> </trans-unit> - <trans-unit id="_msg305"> + <trans-unit id="_msg307"> <source xml:space="preserve">Open the %1 configuration file from the working directory.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">878</context></context-group> </trans-unit> - <trans-unit id="_msg306"> + <trans-unit id="_msg308"> <source xml:space="preserve">Open Configuration File</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">881</context></context-group> </trans-unit> - <trans-unit id="_msg307" approved="yes"> + <trans-unit id="_msg309" approved="yes"> <source xml:space="preserve">Reset all client options to default.</source> <target xml:space="preserve">Reset all client options to default.</target> <context-group purpose="location"><context context-type="linenumber">891</context></context-group> </trans-unit> - <trans-unit id="_msg308" approved="yes"> + <trans-unit id="_msg310" approved="yes"> <source xml:space="preserve">&Reset Options</source> <target xml:space="preserve">&Reset Options</target> <context-group purpose="location"><context context-type="linenumber">894</context></context-group> </trans-unit> - <trans-unit id="_msg309" approved="yes"> + <trans-unit id="_msg311" approved="yes"> <source xml:space="preserve">&Network</source> <target xml:space="preserve">&Network</target> <context-group purpose="location"><context context-type="linenumber">249</context></context-group> </trans-unit> - <trans-unit id="_msg310"> + <trans-unit id="_msg312"> <source xml:space="preserve">Prune &block storage to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">61</context></context-group> </trans-unit> - <trans-unit id="_msg311"> + <trans-unit id="_msg313"> <source xml:space="preserve">GB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg312"> + <trans-unit id="_msg314"> <source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg313"> + <trans-unit id="_msg315"> <source xml:space="preserve">MiB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> - <trans-unit id="_msg314"> + <trans-unit id="_msg316"> <source xml:space="preserve">(0 = auto, <0 = leave that many cores free)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg315"> + <trans-unit id="_msg317"> <source xml:space="preserve">W&allet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">200</context></context-group> </trans-unit> - <trans-unit id="_msg316"> + <trans-unit id="_msg318"> <source xml:space="preserve">Expert</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg317"> + <trans-unit id="_msg319"> <source xml:space="preserve">Enable coin &control features</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg318"> + <trans-unit id="_msg320"> <source xml:space="preserve">If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg319"> + <trans-unit id="_msg321"> <source xml:space="preserve">&Spend unconfirmed change</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg320" approved="yes"> + <trans-unit id="_msg322" approved="yes"> <source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source> <target xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</target> <context-group purpose="location"><context context-type="linenumber">255</context></context-group> </trans-unit> - <trans-unit id="_msg321" approved="yes"> + <trans-unit id="_msg323" approved="yes"> <source xml:space="preserve">Map port using &UPnP</source> <target xml:space="preserve">Map port using &UPnP</target> <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> - <trans-unit id="_msg322"> + <trans-unit id="_msg324"> <source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">265</context></context-group> </trans-unit> - <trans-unit id="_msg323"> + <trans-unit id="_msg325"> <source xml:space="preserve">Map port using NA&T-PMP</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">268</context></context-group> </trans-unit> - <trans-unit id="_msg324"> + <trans-unit id="_msg326"> <source xml:space="preserve">Accept connections from outside.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> - <trans-unit id="_msg325"> + <trans-unit id="_msg327"> <source xml:space="preserve">Allow incomin&g connections</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">278</context></context-group> </trans-unit> - <trans-unit id="_msg326"> + <trans-unit id="_msg328"> <source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> - <trans-unit id="_msg327"> + <trans-unit id="_msg329"> <source xml:space="preserve">&Connect through SOCKS5 proxy (default proxy):</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">288</context></context-group> </trans-unit> - <trans-unit id="_msg328" approved="yes"> + <trans-unit id="_msg330" approved="yes"> <source xml:space="preserve">Proxy &IP:</source> <target xml:space="preserve">Proxy &IP:</target> <context-group purpose="location"><context context-type="linenumber">297</context></context-group> <context-group purpose="location"><context context-type="linenumber">484</context></context-group> </trans-unit> - <trans-unit id="_msg329" approved="yes"> + <trans-unit id="_msg331" approved="yes"> <source xml:space="preserve">&Port:</source> <target xml:space="preserve">&Port:</target> <context-group purpose="location"><context context-type="linenumber">329</context></context-group> <context-group purpose="location"><context context-type="linenumber">516</context></context-group> </trans-unit> - <trans-unit id="_msg330" approved="yes"> + <trans-unit id="_msg332" approved="yes"> <source xml:space="preserve">Port of the proxy (e.g. 9050)</source> <target xml:space="preserve">Port of the proxy (e.g. 9050)</target> <context-group purpose="location"><context context-type="linenumber">354</context></context-group> <context-group purpose="location"><context context-type="linenumber">541</context></context-group> </trans-unit> - <trans-unit id="_msg331"> + <trans-unit id="_msg333"> <source xml:space="preserve">Used for reaching peers via:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">378</context></context-group> </trans-unit> - <trans-unit id="_msg332"> + <trans-unit id="_msg334"> <source xml:space="preserve">IPv4</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">401</context></context-group> </trans-unit> - <trans-unit id="_msg333"> + <trans-unit id="_msg335"> <source xml:space="preserve">IPv6</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">424</context></context-group> </trans-unit> - <trans-unit id="_msg334"> + <trans-unit id="_msg336"> <source xml:space="preserve">Tor</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">447</context></context-group> </trans-unit> - <trans-unit id="_msg335" approved="yes"> + <trans-unit id="_msg337" approved="yes"> <source xml:space="preserve">&Window</source> <target xml:space="preserve">&Window</target> <context-group purpose="location"><context context-type="linenumber">577</context></context-group> </trans-unit> - <trans-unit id="_msg336"> + <trans-unit id="_msg338"> <source xml:space="preserve">Show the icon in the system tray.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">583</context></context-group> </trans-unit> - <trans-unit id="_msg337"> + <trans-unit id="_msg339"> <source xml:space="preserve">&Show tray icon</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">586</context></context-group> </trans-unit> - <trans-unit id="_msg338" approved="yes"> + <trans-unit id="_msg340" approved="yes"> <source xml:space="preserve">Show only a tray icon after minimizing the window.</source> <target xml:space="preserve">Show only a tray icon after minimizing the window.</target> <context-group purpose="location"><context context-type="linenumber">596</context></context-group> </trans-unit> - <trans-unit id="_msg339" approved="yes"> + <trans-unit id="_msg341" approved="yes"> <source xml:space="preserve">&Minimize to the tray instead of the taskbar</source> <target xml:space="preserve">&Minimize to the tray instead of the taskbar</target> <context-group purpose="location"><context context-type="linenumber">599</context></context-group> </trans-unit> - <trans-unit id="_msg340" approved="yes"> + <trans-unit id="_msg342" approved="yes"> <source xml:space="preserve">M&inimize on close</source> <target xml:space="preserve">M&inimize on close</target> <context-group purpose="location"><context context-type="linenumber">609</context></context-group> </trans-unit> - <trans-unit id="_msg341" approved="yes"> + <trans-unit id="_msg343" approved="yes"> <source xml:space="preserve">&Display</source> <target xml:space="preserve">&Display</target> <context-group purpose="location"><context context-type="linenumber">630</context></context-group> </trans-unit> - <trans-unit id="_msg342" approved="yes"> + <trans-unit id="_msg344" approved="yes"> <source xml:space="preserve">User Interface &language:</source> <target xml:space="preserve">User Interface &language:</target> <context-group purpose="location"><context context-type="linenumber">638</context></context-group> </trans-unit> - <trans-unit id="_msg343"> + <trans-unit id="_msg345"> <source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">651</context></context-group> </trans-unit> - <trans-unit id="_msg344" approved="yes"> + <trans-unit id="_msg346" approved="yes"> <source xml:space="preserve">&Unit to show amounts in:</source> <target xml:space="preserve">&Unit to show amounts in:</target> <context-group purpose="location"><context context-type="linenumber">662</context></context-group> </trans-unit> - <trans-unit id="_msg345" approved="yes"> + <trans-unit id="_msg347" approved="yes"> <source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source> <target xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</target> <context-group purpose="location"><context context-type="linenumber">675</context></context-group> </trans-unit> - <trans-unit id="_msg346"> + <trans-unit id="_msg348"> <source xml:space="preserve">Whether to show coin control features or not.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg347"> + <trans-unit id="_msg349"> <source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">472</context></context-group> </trans-unit> - <trans-unit id="_msg348"> + <trans-unit id="_msg350"> <source xml:space="preserve">Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">475</context></context-group> </trans-unit> - <trans-unit id="_msg349"> + <trans-unit id="_msg351"> <source xml:space="preserve">&Third party transaction URLs</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">689</context></context-group> </trans-unit> - <trans-unit id="_msg350"> + <trans-unit id="_msg352"> <source xml:space="preserve">Monospaced font in the Overview tab:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">711</context></context-group> </trans-unit> - <trans-unit id="_msg351"> + <trans-unit id="_msg353"> <source xml:space="preserve">embedded "%1"</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">719</context></context-group> </trans-unit> - <trans-unit id="_msg352"> + <trans-unit id="_msg354"> <source xml:space="preserve">closest matching "%1"</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">768</context></context-group> </trans-unit> - <trans-unit id="_msg353"> + <trans-unit id="_msg355"> <source xml:space="preserve">Options set in this dialog are overridden by the command line or in the configuration file:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">833</context></context-group> </trans-unit> - <trans-unit id="_msg354" approved="yes"> + <trans-unit id="_msg356" approved="yes"> <source xml:space="preserve">&OK</source> <target xml:space="preserve">&OK</target> <context-group purpose="location"><context context-type="linenumber">974</context></context-group> </trans-unit> - <trans-unit id="_msg355" approved="yes"> + <trans-unit id="_msg357" approved="yes"> <source xml:space="preserve">&Cancel</source> <target xml:space="preserve">&Cancel</target> <context-group purpose="location"><context context-type="linenumber">987</context></context-group> @@ -1927,58 +1943,58 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../optionsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> - <trans-unit id="_msg356" approved="yes"> + <trans-unit id="_msg358" approved="yes"> <source xml:space="preserve">default</source> <target xml:space="preserve">default</target> <context-group purpose="location"><context context-type="linenumber">104</context></context-group> </trans-unit> - <trans-unit id="_msg357"> + <trans-unit id="_msg359"> <source xml:space="preserve">none</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">185</context></context-group> </trans-unit> - <trans-unit id="_msg358" approved="yes"> + <trans-unit id="_msg360" approved="yes"> <source xml:space="preserve">Confirm options reset</source> <target xml:space="preserve">Confirm options reset</target> <context-group purpose="location"><context context-type="linenumber">276</context></context-group> </trans-unit> - <trans-unit id="_msg359"> + <trans-unit id="_msg361"> <source xml:space="preserve">Client restart required to activate changes.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">277</context></context-group> <context-group purpose="location"><context context-type="linenumber">334</context></context-group> </trans-unit> - <trans-unit id="_msg360"> + <trans-unit id="_msg362"> <source xml:space="preserve">Client will be shut down. Do you want to proceed?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">277</context></context-group> </trans-unit> - <trans-unit id="_msg361"> + <trans-unit id="_msg363"> <source xml:space="preserve">Configuration options</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">292</context></context-group> </trans-unit> - <trans-unit id="_msg362"> + <trans-unit id="_msg364"> <source xml:space="preserve">The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">293</context></context-group> </trans-unit> - <trans-unit id="_msg363"> + <trans-unit id="_msg365"> <source xml:space="preserve">Error</source> <target xml:space="preserve" state="needs-review-translation">Error</target> <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> - <trans-unit id="_msg364"> + <trans-unit id="_msg366"> <source xml:space="preserve">The configuration file could not be opened.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> - <trans-unit id="_msg365"> + <trans-unit id="_msg367"> <source xml:space="preserve">This change would require a client restart.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">338</context></context-group> </trans-unit> - <trans-unit id="_msg366" approved="yes"> + <trans-unit id="_msg368" approved="yes"> <source xml:space="preserve">The supplied proxy address is invalid.</source> <target xml:space="preserve">The supplied proxy address is invalid.</target> <context-group purpose="location"><context context-type="linenumber">366</context></context-group> @@ -1987,93 +2003,93 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OverviewPage"> - <trans-unit id="_msg367" approved="yes"> + <trans-unit id="_msg369" approved="yes"> <source xml:space="preserve">Form</source> <target xml:space="preserve">Form</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg368" approved="yes"> + <trans-unit id="_msg370" approved="yes"> <source xml:space="preserve">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> <target xml:space="preserve">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.</target> <context-group purpose="location"><context context-type="linenumber">76</context></context-group> <context-group purpose="location"><context context-type="linenumber">411</context></context-group> </trans-unit> - <trans-unit id="_msg369"> + <trans-unit id="_msg371"> <source xml:space="preserve">Watch-only:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> - <trans-unit id="_msg370"> + <trans-unit id="_msg372"> <source xml:space="preserve">Available:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">294</context></context-group> </trans-unit> - <trans-unit id="_msg371" approved="yes"> + <trans-unit id="_msg373" approved="yes"> <source xml:space="preserve">Your current spendable balance</source> <target xml:space="preserve">Your current spendable balance</target> <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> - <trans-unit id="_msg372"> + <trans-unit id="_msg374"> <source xml:space="preserve">Pending:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">339</context></context-group> </trans-unit> - <trans-unit id="_msg373" approved="yes"> + <trans-unit id="_msg375" approved="yes"> <source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> <target xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg374" approved="yes"> + <trans-unit id="_msg376" approved="yes"> <source xml:space="preserve">Immature:</source> <target xml:space="preserve">Immature:</target> <context-group purpose="location"><context context-type="linenumber">239</context></context-group> </trans-unit> - <trans-unit id="_msg375" approved="yes"> + <trans-unit id="_msg377" approved="yes"> <source xml:space="preserve">Mined balance that has not yet matured</source> <target xml:space="preserve">Mined balance that has not yet matured</target> <context-group purpose="location"><context context-type="linenumber">210</context></context-group> </trans-unit> - <trans-unit id="_msg376"> + <trans-unit id="_msg378"> <source xml:space="preserve">Balances</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">60</context></context-group> </trans-unit> - <trans-unit id="_msg377" approved="yes"> + <trans-unit id="_msg379" approved="yes"> <source xml:space="preserve">Total:</source> <target xml:space="preserve">Total:</target> <context-group purpose="location"><context context-type="linenumber">200</context></context-group> </trans-unit> - <trans-unit id="_msg378" approved="yes"> + <trans-unit id="_msg380" approved="yes"> <source xml:space="preserve">Your current total balance</source> <target xml:space="preserve">Your current total balance</target> <context-group purpose="location"><context context-type="linenumber">249</context></context-group> </trans-unit> - <trans-unit id="_msg379"> + <trans-unit id="_msg381"> <source xml:space="preserve">Your current balance in watch-only addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg380"> + <trans-unit id="_msg382"> <source xml:space="preserve">Spendable:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">346</context></context-group> </trans-unit> - <trans-unit id="_msg381"> + <trans-unit id="_msg383"> <source xml:space="preserve">Recent transactions</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">395</context></context-group> </trans-unit> - <trans-unit id="_msg382"> + <trans-unit id="_msg384"> <source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg383"> + <trans-unit id="_msg385"> <source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">158</context></context-group> </trans-unit> - <trans-unit id="_msg384"> + <trans-unit id="_msg386"> <source xml:space="preserve">Current total balance in watch-only addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">268</context></context-group> @@ -2082,41 +2098,41 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../overviewpage.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OverviewPage"> - <trans-unit id="_msg385"> + <trans-unit id="_msg387"> <source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + <context-group purpose="location"><context context-type="linenumber">193</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> - <trans-unit id="_msg386"> + <trans-unit id="_msg388"> <source xml:space="preserve">Dialog</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg387"> + <trans-unit id="_msg389"> <source xml:space="preserve">Sign Tx</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> - <trans-unit id="_msg388"> + <trans-unit id="_msg390"> <source xml:space="preserve">Broadcast Tx</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg389"> + <trans-unit id="_msg391"> <source xml:space="preserve">Copy to Clipboard</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg390"> + <trans-unit id="_msg392"> <source xml:space="preserve">Save…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">129</context></context-group> </trans-unit> - <trans-unit id="_msg391"> + <trans-unit id="_msg393"> <source xml:space="preserve">Close</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">136</context></context-group> @@ -2125,123 +2141,123 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> - <trans-unit id="_msg392"> + <trans-unit id="_msg394"> <source xml:space="preserve">Failed to load transaction: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">55</context></context-group> </trans-unit> - <trans-unit id="_msg393"> + <trans-unit id="_msg395"> <source xml:space="preserve">Failed to sign transaction: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg394"> + <trans-unit id="_msg396"> <source xml:space="preserve">Could not sign any more inputs.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">81</context></context-group> </trans-unit> - <trans-unit id="_msg395"> + <trans-unit id="_msg397"> <source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">83</context></context-group> </trans-unit> - <trans-unit id="_msg396"> + <trans-unit id="_msg398"> <source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> - <trans-unit id="_msg397"> + <trans-unit id="_msg399"> <source xml:space="preserve">Unknown error processing transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg398"> + <trans-unit id="_msg400"> <source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg399"> + <trans-unit id="_msg401"> <source xml:space="preserve">Transaction broadcast failed: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg400"> + <trans-unit id="_msg402"> <source xml:space="preserve">PSBT copied to clipboard.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg401"> + <trans-unit id="_msg403"> <source xml:space="preserve">Save Transaction Data</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">143</context></context-group> </trans-unit> - <trans-unit id="_msg402"> + <trans-unit id="_msg404"> <source xml:space="preserve">Partially Signed Transaction (Binary)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">145</context></context-group> <note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note> </trans-unit> - <trans-unit id="_msg403"> + <trans-unit id="_msg405"> <source xml:space="preserve">PSBT saved to disk.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg404"> + <trans-unit id="_msg406"> <source xml:space="preserve"> * Sends %1 to %2</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">168</context></context-group> </trans-unit> - <trans-unit id="_msg405"> + <trans-unit id="_msg407"> <source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg406"> + <trans-unit id="_msg408"> <source xml:space="preserve">Pays transaction fee: </source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg407"> + <trans-unit id="_msg409"> <source xml:space="preserve">Total Amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">192</context></context-group> </trans-unit> - <trans-unit id="_msg408"> + <trans-unit id="_msg410"> <source xml:space="preserve">or</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">195</context></context-group> </trans-unit> - <trans-unit id="_msg409"> + <trans-unit id="_msg411"> <source xml:space="preserve">Transaction has %1 unsigned inputs.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">201</context></context-group> </trans-unit> - <trans-unit id="_msg410"> + <trans-unit id="_msg412"> <source xml:space="preserve">Transaction is missing some information about inputs.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">243</context></context-group> </trans-unit> - <trans-unit id="_msg411"> + <trans-unit id="_msg413"> <source xml:space="preserve">Transaction still needs signature(s).</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">247</context></context-group> </trans-unit> - <trans-unit id="_msg412"> + <trans-unit id="_msg414"> <source xml:space="preserve">(But this wallet cannot sign transactions.)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg413"> + <trans-unit id="_msg415"> <source xml:space="preserve">(But this wallet does not have the right keys.)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg414"> + <trans-unit id="_msg416"> <source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">261</context></context-group> </trans-unit> - <trans-unit id="_msg415"> + <trans-unit id="_msg417"> <source xml:space="preserve">Transaction status is unknown.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">265</context></context-group> @@ -2250,17 +2266,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../paymentserver.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PaymentServer"> - <trans-unit id="_msg416"> + <trans-unit id="_msg418"> <source xml:space="preserve">Payment request error</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg417"> + <trans-unit id="_msg419"> <source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg418"> + <trans-unit id="_msg420"> <source xml:space="preserve">URI handling</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">224</context></context-group> @@ -2268,12 +2284,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg419"> + <trans-unit id="_msg421"> <source xml:space="preserve">'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">224</context></context-group> </trans-unit> - <trans-unit id="_msg420"> + <trans-unit id="_msg422"> <source xml:space="preserve">Cannot process payment request because BIP70 is not supported. Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored. If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> @@ -2281,12 +2297,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <context-group purpose="location"><context context-type="linenumber">241</context></context-group> <context-group purpose="location"><context context-type="linenumber">264</context></context-group> </trans-unit> - <trans-unit id="_msg421"> + <trans-unit id="_msg423"> <source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">254</context></context-group> </trans-unit> - <trans-unit id="_msg422"> + <trans-unit id="_msg424"> <source xml:space="preserve">Payment request file handling</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">263</context></context-group> @@ -2295,49 +2311,49 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../peertablemodel.h" datatype="c" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PeerTableModel"> - <trans-unit id="_msg423"> + <trans-unit id="_msg425"> <source xml:space="preserve">User Agent</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">101</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which contains the peer's User Agent string.</note> </trans-unit> - <trans-unit id="_msg424"> + <trans-unit id="_msg426"> <source xml:space="preserve">Ping</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">92</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which indicates the current latency of the connection with the peer.</note> </trans-unit> - <trans-unit id="_msg425"> + <trans-unit id="_msg427"> <source xml:space="preserve">Peer</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which contains a unique number used to identify a connection.</note> </trans-unit> - <trans-unit id="_msg426"> + <trans-unit id="_msg428"> <source xml:space="preserve">Sent</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</note> </trans-unit> - <trans-unit id="_msg427"> + <trans-unit id="_msg429"> <source xml:space="preserve">Received</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have received from the peer.</note> </trans-unit> - <trans-unit id="_msg428"> + <trans-unit id="_msg430"> <source xml:space="preserve">Address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">83</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</note> </trans-unit> - <trans-unit id="_msg429"> + <trans-unit id="_msg431"> <source xml:space="preserve">Type</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</note> </trans-unit> - <trans-unit id="_msg430"> + <trans-unit id="_msg432"> <source xml:space="preserve">Network</source> <target xml:space="preserve" state="needs-review-translation">Network</target> <context-group purpose="location"><context context-type="linenumber">89</context></context-group> @@ -2347,7 +2363,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../bitcoinunits.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="QObject"> - <trans-unit id="_msg431"> + <trans-unit id="_msg433"> <source xml:space="preserve">Amount</source> <target xml:space="preserve" state="needs-review-translation">Amount</target> <context-group purpose="location"><context context-type="linenumber">213</context></context-group> @@ -2356,219 +2372,219 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../guiutil.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="QObject"> - <trans-unit id="_msg432"> + <trans-unit id="_msg434"> <source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">118</context></context-group> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg433"> + <trans-unit id="_msg435"> <source xml:space="preserve">Unroutable</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">658</context></context-group> + <context-group purpose="location"><context context-type="linenumber">660</context></context-group> </trans-unit> - <trans-unit id="_msg434"> + <trans-unit id="_msg436"> <source xml:space="preserve">Internal</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">664</context></context-group> + <context-group purpose="location"><context context-type="linenumber">666</context></context-group> </trans-unit> - <trans-unit id="_msg435"> + <trans-unit id="_msg437"> <source xml:space="preserve">Inbound</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">674</context></context-group> + <context-group purpose="location"><context context-type="linenumber">676</context></context-group> </trans-unit> - <trans-unit id="_msg436"> + <trans-unit id="_msg438"> <source xml:space="preserve">Outbound</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">674</context></context-group> + <context-group purpose="location"><context context-type="linenumber">676</context></context-group> </trans-unit> - <trans-unit id="_msg437"> + <trans-unit id="_msg439"> <source xml:space="preserve">Full Relay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">678</context></context-group> + <context-group purpose="location"><context context-type="linenumber">680</context></context-group> </trans-unit> - <trans-unit id="_msg438"> + <trans-unit id="_msg440"> <source xml:space="preserve">Block Relay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">679</context></context-group> + <context-group purpose="location"><context context-type="linenumber">681</context></context-group> </trans-unit> - <trans-unit id="_msg439"> + <trans-unit id="_msg441"> <source xml:space="preserve">Manual</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">680</context></context-group> + <context-group purpose="location"><context context-type="linenumber">682</context></context-group> </trans-unit> - <trans-unit id="_msg440"> + <trans-unit id="_msg442"> <source xml:space="preserve">Feeler</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">681</context></context-group> + <context-group purpose="location"><context context-type="linenumber">683</context></context-group> </trans-unit> - <trans-unit id="_msg441"> + <trans-unit id="_msg443"> <source xml:space="preserve">Address Fetch</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">682</context></context-group> + <context-group purpose="location"><context context-type="linenumber">684</context></context-group> </trans-unit> - <trans-unit id="_msg442"> + <trans-unit id="_msg444"> <source xml:space="preserve">%1 d</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">696</context></context-group> + <context-group purpose="location"><context context-type="linenumber">698</context></context-group> </trans-unit> - <trans-unit id="_msg443"> + <trans-unit id="_msg445"> <source xml:space="preserve">%1 h</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">698</context></context-group> + <context-group purpose="location"><context context-type="linenumber">700</context></context-group> </trans-unit> - <trans-unit id="_msg444"> + <trans-unit id="_msg446"> <source xml:space="preserve">%1 m</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">700</context></context-group> + <context-group purpose="location"><context context-type="linenumber">702</context></context-group> </trans-unit> - <trans-unit id="_msg445"> + <trans-unit id="_msg447"> <source xml:space="preserve">%1 s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">702</context></context-group> - <context-group purpose="location"><context context-type="linenumber">730</context></context-group> + <context-group purpose="location"><context context-type="linenumber">704</context></context-group> + <context-group purpose="location"><context context-type="linenumber">732</context></context-group> </trans-unit> - <trans-unit id="_msg446"> + <trans-unit id="_msg448"> <source xml:space="preserve">None</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">718</context></context-group> + <context-group purpose="location"><context context-type="linenumber">720</context></context-group> </trans-unit> - <trans-unit id="_msg447"> + <trans-unit id="_msg449"> <source xml:space="preserve">N/A</source> <target xml:space="preserve" state="needs-review-translation">N/A</target> - <context-group purpose="location"><context context-type="linenumber">724</context></context-group> + <context-group purpose="location"><context context-type="linenumber">726</context></context-group> </trans-unit> - <trans-unit id="_msg448"> + <trans-unit id="_msg450"> <source xml:space="preserve">%1 ms</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">725</context></context-group> + <context-group purpose="location"><context context-type="linenumber">727</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">743</context></context-group> - <trans-unit id="_msg449[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">745</context></context-group> + <trans-unit id="_msg451[0]" approved="yes"> <source xml:space="preserve">%n second(s)</source> <target xml:space="preserve">%n second</target> </trans-unit> - <trans-unit id="_msg449[1]" approved="yes"> + <trans-unit id="_msg451[1]" approved="yes"> <source xml:space="preserve">%n second(s)</source> <target xml:space="preserve">%n seconds</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">747</context></context-group> - <trans-unit id="_msg450[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">749</context></context-group> + <trans-unit id="_msg452[0]" approved="yes"> <source xml:space="preserve">%n minute(s)</source> <target xml:space="preserve">%n minute</target> </trans-unit> - <trans-unit id="_msg450[1]" approved="yes"> + <trans-unit id="_msg452[1]" approved="yes"> <source xml:space="preserve">%n minute(s)</source> <target xml:space="preserve">%n minutes</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">751</context></context-group> - <trans-unit id="_msg451[0]"> + <context-group purpose="location"><context context-type="linenumber">753</context></context-group> + <trans-unit id="_msg453[0]"> <source xml:space="preserve">%n hour(s)</source> <target xml:space="preserve" state="needs-review-translation">%n hour</target> </trans-unit> - <trans-unit id="_msg451[1]"> + <trans-unit id="_msg453[1]"> <source xml:space="preserve">%n hour(s)</source> <target xml:space="preserve" state="needs-review-translation">%n hours</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">755</context></context-group> - <trans-unit id="_msg452[0]"> + <context-group purpose="location"><context context-type="linenumber">757</context></context-group> + <trans-unit id="_msg454[0]"> <source xml:space="preserve">%n day(s)</source> <target xml:space="preserve" state="needs-review-translation">%n day</target> </trans-unit> - <trans-unit id="_msg452[1]"> + <trans-unit id="_msg454[1]"> <source xml:space="preserve">%n day(s)</source> <target xml:space="preserve" state="needs-review-translation">%n days</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">759</context></context-group> - <context-group purpose="location"><context context-type="linenumber">765</context></context-group> - <trans-unit id="_msg453[0]"> + <context-group purpose="location"><context context-type="linenumber">761</context></context-group> + <context-group purpose="location"><context context-type="linenumber">767</context></context-group> + <trans-unit id="_msg455[0]"> <source xml:space="preserve">%n week(s)</source> <target xml:space="preserve" state="needs-review-translation">%n week</target> </trans-unit> - <trans-unit id="_msg453[1]"> + <trans-unit id="_msg455[1]"> <source xml:space="preserve">%n week(s)</source> <target xml:space="preserve" state="needs-review-translation">%n weeks</target> </trans-unit> </group> - <trans-unit id="_msg454"> + <trans-unit id="_msg456"> <source xml:space="preserve">%1 and %2</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">765</context></context-group> + <context-group purpose="location"><context context-type="linenumber">767</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">765</context></context-group> - <trans-unit id="_msg455[0]"> + <context-group purpose="location"><context context-type="linenumber">767</context></context-group> + <trans-unit id="_msg457[0]"> <source xml:space="preserve">%n year(s)</source> <target xml:space="preserve" state="needs-review-translation">%n year</target> </trans-unit> - <trans-unit id="_msg455[1]"> + <trans-unit id="_msg457[1]"> <source xml:space="preserve">%n year(s)</source> <target xml:space="preserve" state="needs-review-translation">%n years</target> </trans-unit> </group> - <trans-unit id="_msg456"> + <trans-unit id="_msg458"> <source xml:space="preserve">%1 B</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">773</context></context-group> + <context-group purpose="location"><context context-type="linenumber">775</context></context-group> </trans-unit> - <trans-unit id="_msg457"> + <trans-unit id="_msg459"> <source xml:space="preserve">%1 kB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">775</context></context-group> + <context-group purpose="location"><context context-type="linenumber">777</context></context-group> </trans-unit> - <trans-unit id="_msg458"> + <trans-unit id="_msg460"> <source xml:space="preserve">%1 MB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">777</context></context-group> + <context-group purpose="location"><context context-type="linenumber">779</context></context-group> </trans-unit> - <trans-unit id="_msg459"> + <trans-unit id="_msg461"> <source xml:space="preserve">%1 GB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">779</context></context-group> + <context-group purpose="location"><context context-type="linenumber">781</context></context-group> </trans-unit> </group> </body></file> <file original="../qrimagewidget.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="QRImageWidget"> - <trans-unit id="_msg460"> + <trans-unit id="_msg462"> <source xml:space="preserve">Save Image…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">30</context></context-group> </trans-unit> - <trans-unit id="_msg461"> + <trans-unit id="_msg463"> <source xml:space="preserve">Copy Image</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">31</context></context-group> </trans-unit> - <trans-unit id="_msg462"> + <trans-unit id="_msg464"> <source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">42</context></context-group> </trans-unit> - <trans-unit id="_msg463"> + <trans-unit id="_msg465"> <source xml:space="preserve">Error encoding URI into QR Code.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg464"> + <trans-unit id="_msg466"> <source xml:space="preserve">QR code support not available.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg465"> + <trans-unit id="_msg467"> <source xml:space="preserve">Save QR Code</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg466"> + <trans-unit id="_msg468"> <source xml:space="preserve">PNG Image</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">123</context></context-group> @@ -2578,7 +2594,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg467" approved="yes"> + <trans-unit id="_msg469" approved="yes"> <source xml:space="preserve">N/A</source> <target xml:space="preserve">N/A</target> <context-group purpose="location"><context context-type="linenumber">75</context></context-group> @@ -2615,324 +2631,324 @@ If you are receiving this error you should request the merchant provide a BIP21 <context-group purpose="location"><context context-type="linenumber">1565</context></context-group> <context-group purpose="location"><context context-type="linenumber">1588</context></context-group> <context-group purpose="location"><context context-type="linenumber">1614</context></context-group> - <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">137</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg468" approved="yes"> + <trans-unit id="_msg470" approved="yes"> <source xml:space="preserve">Client version</source> <target xml:space="preserve">Client version</target> <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> - <trans-unit id="_msg469" approved="yes"> + <trans-unit id="_msg471" approved="yes"> <source xml:space="preserve">&Information</source> <target xml:space="preserve">&Information</target> <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg470"> + <trans-unit id="_msg472"> <source xml:space="preserve">General</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg471"> + <trans-unit id="_msg473"> <source xml:space="preserve">Datadir</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">114</context></context-group> </trans-unit> - <trans-unit id="_msg472"> + <trans-unit id="_msg474"> <source xml:space="preserve">To specify a non-default location of the data directory use the '%1' option.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> - <trans-unit id="_msg473"> + <trans-unit id="_msg475"> <source xml:space="preserve">Blocksdir</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">143</context></context-group> </trans-unit> - <trans-unit id="_msg474"> + <trans-unit id="_msg476"> <source xml:space="preserve">To specify a non-default location of the blocks directory use the '%1' option.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">153</context></context-group> </trans-unit> - <trans-unit id="_msg475" approved="yes"> + <trans-unit id="_msg477" approved="yes"> <source xml:space="preserve">Startup time</source> <target xml:space="preserve">Startup time</target> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg476" approved="yes"> + <trans-unit id="_msg478" approved="yes"> <source xml:space="preserve">Network</source> <target xml:space="preserve">Network</target> <context-group purpose="location"><context context-type="linenumber">201</context></context-group> <context-group purpose="location"><context context-type="linenumber">1123</context></context-group> </trans-unit> - <trans-unit id="_msg477"> + <trans-unit id="_msg479"> <source xml:space="preserve">Name</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">208</context></context-group> </trans-unit> - <trans-unit id="_msg478" approved="yes"> + <trans-unit id="_msg480" approved="yes"> <source xml:space="preserve">Number of connections</source> <target xml:space="preserve">Number of connections</target> <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> - <trans-unit id="_msg479" approved="yes"> + <trans-unit id="_msg481" approved="yes"> <source xml:space="preserve">Block chain</source> <target xml:space="preserve">Block chain</target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg480"> + <trans-unit id="_msg482"> <source xml:space="preserve">Memory Pool</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> - <trans-unit id="_msg481"> + <trans-unit id="_msg483"> <source xml:space="preserve">Current number of transactions</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg482"> + <trans-unit id="_msg484"> <source xml:space="preserve">Memory usage</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">349</context></context-group> </trans-unit> - <trans-unit id="_msg483"> + <trans-unit id="_msg485"> <source xml:space="preserve">Wallet: </source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">443</context></context-group> </trans-unit> - <trans-unit id="_msg484"> + <trans-unit id="_msg486"> <source xml:space="preserve">(none)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">454</context></context-group> </trans-unit> - <trans-unit id="_msg485"> + <trans-unit id="_msg487"> <source xml:space="preserve">&Reset</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">695</context></context-group> </trans-unit> - <trans-unit id="_msg486"> + <trans-unit id="_msg488"> <source xml:space="preserve">Received</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">775</context></context-group> <context-group purpose="location"><context context-type="linenumber">1483</context></context-group> </trans-unit> - <trans-unit id="_msg487"> + <trans-unit id="_msg489"> <source xml:space="preserve">Sent</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">855</context></context-group> <context-group purpose="location"><context context-type="linenumber">1460</context></context-group> </trans-unit> - <trans-unit id="_msg488"> + <trans-unit id="_msg490"> <source xml:space="preserve">&Peers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">896</context></context-group> </trans-unit> - <trans-unit id="_msg489"> + <trans-unit id="_msg491"> <source xml:space="preserve">Banned peers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">972</context></context-group> </trans-unit> - <trans-unit id="_msg490"> + <trans-unit id="_msg492"> <source xml:space="preserve">Select a peer to view detailed information.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1040</context></context-group> - <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1046</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1091</context></context-group> </trans-unit> - <trans-unit id="_msg491"> + <trans-unit id="_msg493"> <source xml:space="preserve">Version</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1146</context></context-group> </trans-unit> - <trans-unit id="_msg492"> + <trans-unit id="_msg494"> <source xml:space="preserve">Starting Block</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1270</context></context-group> </trans-unit> - <trans-unit id="_msg493"> + <trans-unit id="_msg495"> <source xml:space="preserve">Synced Headers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1293</context></context-group> </trans-unit> - <trans-unit id="_msg494"> + <trans-unit id="_msg496"> <source xml:space="preserve">Synced Blocks</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1316</context></context-group> </trans-unit> - <trans-unit id="_msg495"> + <trans-unit id="_msg497"> <source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1601</context></context-group> </trans-unit> - <trans-unit id="_msg496"> + <trans-unit id="_msg498"> <source xml:space="preserve">Mapped AS</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1604</context></context-group> </trans-unit> - <trans-unit id="_msg497"> + <trans-unit id="_msg499"> <source xml:space="preserve">User Agent</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> <context-group purpose="location"><context context-type="linenumber">1169</context></context-group> </trans-unit> - <trans-unit id="_msg498"> + <trans-unit id="_msg500"> <source xml:space="preserve">Node window</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg499"> + <trans-unit id="_msg501"> <source xml:space="preserve">Current block height</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">267</context></context-group> </trans-unit> - <trans-unit id="_msg500"> + <trans-unit id="_msg502"> <source xml:space="preserve">Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">397</context></context-group> </trans-unit> - <trans-unit id="_msg501"> + <trans-unit id="_msg503"> <source xml:space="preserve">Decrease font size</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">481</context></context-group> </trans-unit> - <trans-unit id="_msg502"> + <trans-unit id="_msg504"> <source xml:space="preserve">Increase font size</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">513</context></context-group> </trans-unit> - <trans-unit id="_msg503"> + <trans-unit id="_msg505"> <source xml:space="preserve">Permissions</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1071</context></context-group> </trans-unit> - <trans-unit id="_msg504"> + <trans-unit id="_msg506"> <source xml:space="preserve">The direction and type of peer connection: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1094</context></context-group> </trans-unit> - <trans-unit id="_msg505"> + <trans-unit id="_msg507"> <source xml:space="preserve">Direction/Type</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1097</context></context-group> </trans-unit> - <trans-unit id="_msg506"> + <trans-unit id="_msg508"> <source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1120</context></context-group> </trans-unit> - <trans-unit id="_msg507"> + <trans-unit id="_msg509"> <source xml:space="preserve">Services</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1192</context></context-group> </trans-unit> - <trans-unit id="_msg508"> + <trans-unit id="_msg510"> <source xml:space="preserve">Whether the peer requested us to relay transactions.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1218</context></context-group> </trans-unit> - <trans-unit id="_msg509"> + <trans-unit id="_msg511"> <source xml:space="preserve">Wants Tx Relay</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1221</context></context-group> </trans-unit> - <trans-unit id="_msg510"> + <trans-unit id="_msg512"> <source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1244</context></context-group> </trans-unit> - <trans-unit id="_msg511"> + <trans-unit id="_msg513"> <source xml:space="preserve">High Bandwidth</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1247</context></context-group> </trans-unit> - <trans-unit id="_msg512"> + <trans-unit id="_msg514"> <source xml:space="preserve">Connection Time</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1339</context></context-group> </trans-unit> - <trans-unit id="_msg513"> + <trans-unit id="_msg515"> <source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1362</context></context-group> </trans-unit> - <trans-unit id="_msg514"> + <trans-unit id="_msg516"> <source xml:space="preserve">Last Block</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1365</context></context-group> </trans-unit> - <trans-unit id="_msg515"> + <trans-unit id="_msg517"> <source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1388</context></context-group> </trans-unit> - <trans-unit id="_msg516"> + <trans-unit id="_msg518"> <source xml:space="preserve">Last Tx</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1391</context></context-group> </trans-unit> - <trans-unit id="_msg517"> + <trans-unit id="_msg519"> <source xml:space="preserve">Last Send</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1414</context></context-group> </trans-unit> - <trans-unit id="_msg518"> + <trans-unit id="_msg520"> <source xml:space="preserve">Last Receive</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1437</context></context-group> </trans-unit> - <trans-unit id="_msg519"> + <trans-unit id="_msg521"> <source xml:space="preserve">Ping Time</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1506</context></context-group> </trans-unit> - <trans-unit id="_msg520"> + <trans-unit id="_msg522"> <source xml:space="preserve">The duration of a currently outstanding ping.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1529</context></context-group> </trans-unit> - <trans-unit id="_msg521"> + <trans-unit id="_msg523"> <source xml:space="preserve">Ping Wait</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1532</context></context-group> </trans-unit> - <trans-unit id="_msg522"> + <trans-unit id="_msg524"> <source xml:space="preserve">Min Ping</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1555</context></context-group> </trans-unit> - <trans-unit id="_msg523"> + <trans-unit id="_msg525"> <source xml:space="preserve">Time Offset</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1578</context></context-group> </trans-unit> - <trans-unit id="_msg524" approved="yes"> + <trans-unit id="_msg526" approved="yes"> <source xml:space="preserve">Last block time</source> <target xml:space="preserve">Last block time</target> <context-group purpose="location"><context context-type="linenumber">290</context></context-group> </trans-unit> - <trans-unit id="_msg525" approved="yes"> + <trans-unit id="_msg527" approved="yes"> <source xml:space="preserve">&Open</source> <target xml:space="preserve">&Open</target> <context-group purpose="location"><context context-type="linenumber">400</context></context-group> </trans-unit> - <trans-unit id="_msg526" approved="yes"> + <trans-unit id="_msg528" approved="yes"> <source xml:space="preserve">&Console</source> <target xml:space="preserve">&Console</target> <context-group purpose="location"><context context-type="linenumber">426</context></context-group> </trans-unit> - <trans-unit id="_msg527"> + <trans-unit id="_msg529"> <source xml:space="preserve">&Network Traffic</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">643</context></context-group> </trans-unit> - <trans-unit id="_msg528"> + <trans-unit id="_msg530"> <source xml:space="preserve">Totals</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">711</context></context-group> </trans-unit> - <trans-unit id="_msg529" approved="yes"> + <trans-unit id="_msg531" approved="yes"> <source xml:space="preserve">Debug log file</source> <target xml:space="preserve">Debug log file</target> <context-group purpose="location"><context context-type="linenumber">390</context></context-group> </trans-unit> - <trans-unit id="_msg530" approved="yes"> + <trans-unit id="_msg532" approved="yes"> <source xml:space="preserve">Clear console</source> <target xml:space="preserve">Clear console</target> <context-group purpose="location"><context context-type="linenumber">545</context></context-group> @@ -2941,305 +2957,293 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../rpcconsole.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg531"> + <trans-unit id="_msg533"> <source xml:space="preserve">In:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">865</context></context-group> + <context-group purpose="location"><context context-type="linenumber">890</context></context-group> </trans-unit> - <trans-unit id="_msg532"> + <trans-unit id="_msg534"> <source xml:space="preserve">Out:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">866</context></context-group> + <context-group purpose="location"><context context-type="linenumber">891</context></context-group> </trans-unit> - <trans-unit id="_msg533"> + <trans-unit id="_msg535"> <source xml:space="preserve">Inbound: initiated by peer</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">474</context></context-group> </trans-unit> - <trans-unit id="_msg534"> + <trans-unit id="_msg536"> <source xml:space="preserve">Outbound Full Relay: default</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">475</context></context-group> </trans-unit> - <trans-unit id="_msg535"> + <trans-unit id="_msg537"> <source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">476</context></context-group> </trans-unit> - <trans-unit id="_msg536"> + <trans-unit id="_msg538"> <source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">477</context></context-group> </trans-unit> - <trans-unit id="_msg537"> + <trans-unit id="_msg539"> <source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">481</context></context-group> </trans-unit> - <trans-unit id="_msg538"> + <trans-unit id="_msg540"> <source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">482</context></context-group> </trans-unit> - <trans-unit id="_msg539"> + <trans-unit id="_msg541"> <source xml:space="preserve">we selected the peer for high bandwidth relay</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">486</context></context-group> </trans-unit> - <trans-unit id="_msg540"> + <trans-unit id="_msg542"> <source xml:space="preserve">the peer selected us for high bandwidth relay</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">487</context></context-group> </trans-unit> - <trans-unit id="_msg541"> + <trans-unit id="_msg543"> <source xml:space="preserve">no high bandwidth relay selected</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">488</context></context-group> </trans-unit> - <trans-unit id="_msg542"> + <trans-unit id="_msg544"> <source xml:space="preserve">Ctrl++</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">501</context></context-group> <note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg543"> + <trans-unit id="_msg545"> <source xml:space="preserve">Ctrl+=</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">503</context></context-group> <note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg544"> + <trans-unit id="_msg546"> <source xml:space="preserve">Ctrl+-</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">507</context></context-group> <note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg545"> + <trans-unit id="_msg547"> <source xml:space="preserve">Ctrl+_</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">509</context></context-group> <note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg546"> - <source xml:space="preserve">Welcome to the %1 RPC console.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">820</context></context-group> - </trans-unit> - <trans-unit id="_msg547"> - <source xml:space="preserve">Use up and down arrows to navigate history, and %1 to clear screen.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">822</context></context-group> - </trans-unit> <trans-unit id="_msg548"> - <source xml:space="preserve">Use %1 and %2 to increase or decrease the font size.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">825</context></context-group> - </trans-unit> - <trans-unit id="_msg549"> - <source xml:space="preserve">Type %1 for an overview of available commands.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">829</context></context-group> - </trans-unit> - <trans-unit id="_msg550"> - <source xml:space="preserve">For more information on using this console type %1.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">831</context></context-group> - </trans-unit> - <trans-unit id="_msg551"> - <source xml:space="preserve">WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">833</context></context-group> - </trans-unit> - <trans-unit id="_msg552"> <source xml:space="preserve">Network activity disabled</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">869</context></context-group> + <context-group purpose="location"><context context-type="linenumber">894</context></context-group> </trans-unit> - <trans-unit id="_msg553"> + <trans-unit id="_msg549"> <source xml:space="preserve">Executing command without any wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">935</context></context-group> + <context-group purpose="location"><context context-type="linenumber">971</context></context-group> </trans-unit> - <trans-unit id="_msg554"> + <trans-unit id="_msg550"> <source xml:space="preserve">Executing command using "%1" wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">933</context></context-group> + <context-group purpose="location"><context context-type="linenumber">969</context></context-group> </trans-unit> - <trans-unit id="_msg555"> + <trans-unit id="_msg551"> <source xml:space="preserve">Disconnect</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">650</context></context-group> </trans-unit> - <trans-unit id="_msg556"> + <trans-unit id="_msg552"> <source xml:space="preserve">1 hour</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">651</context></context-group> </trans-unit> - <trans-unit id="_msg557"> + <trans-unit id="_msg553"> <source xml:space="preserve">1 day</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">652</context></context-group> </trans-unit> - <trans-unit id="_msg558"> + <trans-unit id="_msg554"> <source xml:space="preserve">1 week</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">653</context></context-group> </trans-unit> - <trans-unit id="_msg559"> + <trans-unit id="_msg555"> <source xml:space="preserve">1 year</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">654</context></context-group> </trans-unit> - <trans-unit id="_msg560"> + <trans-unit id="_msg556"> <source xml:space="preserve">Unban</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">673</context></context-group> </trans-unit> - <trans-unit id="_msg561"> + <trans-unit id="_msg557"> + <source xml:space="preserve">Welcome to the %1 RPC console. +Use up and down arrows to navigate history, and %2 to clear screen. +Use %3 and %4 to increase or decrease the font size. +Type %5 for an overview of available commands. +For more information on using this console, type %6. + +%7WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.%8</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">823</context></context-group> + <note annotates="source" from="developer">RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</note> + </trans-unit> + <trans-unit id="_msg558"> + <source xml:space="preserve">Executing…</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">979</context></context-group> + <note annotates="source" from="developer">A console message indicating an entered command is currently being executed.</note> + </trans-unit> + <trans-unit id="_msg559"> <source xml:space="preserve">(peer: %1)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1052</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1097</context></context-group> </trans-unit> - <trans-unit id="_msg562"> + <trans-unit id="_msg560"> <source xml:space="preserve">via %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1054</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1099</context></context-group> </trans-unit> </group> </body></file> <file original="../rpcconsole.h" datatype="c" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg563"> + <trans-unit id="_msg561"> <source xml:space="preserve">Yes</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg564"> + <trans-unit id="_msg562"> <source xml:space="preserve">No</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg565"> + <trans-unit id="_msg563"> <source xml:space="preserve">To</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg566"> + <trans-unit id="_msg564"> <source xml:space="preserve">From</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg567"> + <trans-unit id="_msg565"> <source xml:space="preserve">Ban for</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">137</context></context-group> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg568"> + <trans-unit id="_msg566"> <source xml:space="preserve">Never</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg569"> + <trans-unit id="_msg567"> <source xml:space="preserve">Unknown</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">137</context></context-group> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog"> - <trans-unit id="_msg570"> + <trans-unit id="_msg568"> <source xml:space="preserve">&Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg571"> + <trans-unit id="_msg569"> <source xml:space="preserve">&Label:</source> <target xml:space="preserve" state="needs-review-translation">&Label:</target> <context-group purpose="location"><context context-type="linenumber">83</context></context-group> </trans-unit> - <trans-unit id="_msg572"> + <trans-unit id="_msg570"> <source xml:space="preserve">&Message:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">53</context></context-group> </trans-unit> - <trans-unit id="_msg573"> + <trans-unit id="_msg571"> <source xml:space="preserve">An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg574"> + <trans-unit id="_msg572"> <source xml:space="preserve">An optional label to associate with the new receiving address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg575"> + <trans-unit id="_msg573"> <source xml:space="preserve">Use this form to request payments. All fields are <b>optional</b>.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg576"> + <trans-unit id="_msg574"> <source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">34</context></context-group> <context-group purpose="location"><context context-type="linenumber">193</context></context-group> </trans-unit> - <trans-unit id="_msg577"> + <trans-unit id="_msg575"> <source xml:space="preserve">An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg578"> + <trans-unit id="_msg576"> <source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg579"> + <trans-unit id="_msg577"> <source xml:space="preserve">&Create new receiving address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg580"> + <trans-unit id="_msg578"> <source xml:space="preserve">Clear all fields of the form.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">134</context></context-group> </trans-unit> - <trans-unit id="_msg581"> + <trans-unit id="_msg579"> <source xml:space="preserve">Clear</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg582"> + <trans-unit id="_msg580"> <source xml:space="preserve">Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg583"> + <trans-unit id="_msg581"> <source xml:space="preserve">Generate native segwit (Bech32) address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> - <trans-unit id="_msg584"> + <trans-unit id="_msg582"> <source xml:space="preserve">Requested payments history</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> - <trans-unit id="_msg585"> + <trans-unit id="_msg583"> <source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> - <trans-unit id="_msg586"> + <trans-unit id="_msg584"> <source xml:space="preserve">Show</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">307</context></context-group> </trans-unit> - <trans-unit id="_msg587"> + <trans-unit id="_msg585"> <source xml:space="preserve">Remove the selected entries from the list</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg588"> + <trans-unit id="_msg586"> <source xml:space="preserve">Remove</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">327</context></context-group> @@ -3248,37 +3252,37 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog"> - <trans-unit id="_msg589"> + <trans-unit id="_msg587"> <source xml:space="preserve">Copy URI</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg590"> + <trans-unit id="_msg588"> <source xml:space="preserve">Copy address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">48</context></context-group> </trans-unit> - <trans-unit id="_msg591"> + <trans-unit id="_msg589"> <source xml:space="preserve">Copy label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg592"> + <trans-unit id="_msg590"> <source xml:space="preserve">Copy message</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg593"> + <trans-unit id="_msg591"> <source xml:space="preserve">Copy amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg594"> + <trans-unit id="_msg592"> <source xml:space="preserve">Could not unlock wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg595"> + <trans-unit id="_msg593"> <source xml:space="preserve">Could not generate new %1 address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">181</context></context-group> @@ -3287,52 +3291,52 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog"> - <trans-unit id="_msg596"> + <trans-unit id="_msg594"> <source xml:space="preserve">Request payment to …</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg597"> + <trans-unit id="_msg595"> <source xml:space="preserve">Address:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg598"> + <trans-unit id="_msg596"> <source xml:space="preserve">Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">119</context></context-group> </trans-unit> - <trans-unit id="_msg599"> + <trans-unit id="_msg597"> <source xml:space="preserve">Label:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg600"> + <trans-unit id="_msg598"> <source xml:space="preserve">Message:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg601"> + <trans-unit id="_msg599"> <source xml:space="preserve">Wallet:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg602"> + <trans-unit id="_msg600"> <source xml:space="preserve">Copy &URI</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg603"> + <trans-unit id="_msg601"> <source xml:space="preserve">Copy &Address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg604"> + <trans-unit id="_msg602"> <source xml:space="preserve">&Save Image…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg605"> + <trans-unit id="_msg603"> <source xml:space="preserve">Payment information</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> @@ -3341,7 +3345,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog"> - <trans-unit id="_msg606"> + <trans-unit id="_msg604"> <source xml:space="preserve">Request payment to %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> @@ -3350,37 +3354,37 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel"> - <trans-unit id="_msg607"> + <trans-unit id="_msg605"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">30</context></context-group> </trans-unit> - <trans-unit id="_msg608"> + <trans-unit id="_msg606"> <source xml:space="preserve">Label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">30</context></context-group> </trans-unit> - <trans-unit id="_msg609"> + <trans-unit id="_msg607"> <source xml:space="preserve">Message</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">30</context></context-group> </trans-unit> - <trans-unit id="_msg610"> + <trans-unit id="_msg608"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg611"> + <trans-unit id="_msg609"> <source xml:space="preserve">(no message)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg612"> + <trans-unit id="_msg610"> <source xml:space="preserve">(no amount requested)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg613"> + <trans-unit id="_msg611"> <source xml:space="preserve">Requested</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">131</context></context-group> @@ -3389,190 +3393,190 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> - <trans-unit id="_msg614" approved="yes"> + <trans-unit id="_msg612" approved="yes"> <source xml:space="preserve">Send Coins</source> <target xml:space="preserve">Send Coins</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">674</context></context-group> </trans-unit> - <trans-unit id="_msg615"> + <trans-unit id="_msg613"> <source xml:space="preserve">Coin Control Features</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg616"> + <trans-unit id="_msg614"> <source xml:space="preserve">automatically selected</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg617"> + <trans-unit id="_msg615"> <source xml:space="preserve">Insufficient funds!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg618"> + <trans-unit id="_msg616"> <source xml:space="preserve">Quantity:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> - <trans-unit id="_msg619"> + <trans-unit id="_msg617"> <source xml:space="preserve">Bytes:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> - <trans-unit id="_msg620"> + <trans-unit id="_msg618"> <source xml:space="preserve">Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">311</context></context-group> </trans-unit> - <trans-unit id="_msg621"> + <trans-unit id="_msg619"> <source xml:space="preserve">Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">391</context></context-group> </trans-unit> - <trans-unit id="_msg622"> + <trans-unit id="_msg620"> <source xml:space="preserve">After Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">442</context></context-group> </trans-unit> - <trans-unit id="_msg623"> + <trans-unit id="_msg621"> <source xml:space="preserve">Change:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">474</context></context-group> </trans-unit> - <trans-unit id="_msg624"> + <trans-unit id="_msg622"> <source xml:space="preserve">If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">518</context></context-group> </trans-unit> - <trans-unit id="_msg625"> + <trans-unit id="_msg623"> <source xml:space="preserve">Custom change address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">521</context></context-group> </trans-unit> - <trans-unit id="_msg626"> + <trans-unit id="_msg624"> <source xml:space="preserve">Transaction Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">727</context></context-group> </trans-unit> - <trans-unit id="_msg627"> + <trans-unit id="_msg625"> <source xml:space="preserve">Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">765</context></context-group> </trans-unit> - <trans-unit id="_msg628"> + <trans-unit id="_msg626"> <source xml:space="preserve">Warning: Fee estimation is currently not possible.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">774</context></context-group> </trans-unit> - <trans-unit id="_msg629"> + <trans-unit id="_msg627"> <source xml:space="preserve">per kilobyte</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">856</context></context-group> </trans-unit> - <trans-unit id="_msg630"> + <trans-unit id="_msg628"> <source xml:space="preserve">Hide</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">803</context></context-group> </trans-unit> - <trans-unit id="_msg631"> + <trans-unit id="_msg629"> <source xml:space="preserve">Recommended:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">915</context></context-group> </trans-unit> - <trans-unit id="_msg632"> + <trans-unit id="_msg630"> <source xml:space="preserve">Custom:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">945</context></context-group> </trans-unit> - <trans-unit id="_msg633" approved="yes"> + <trans-unit id="_msg631" approved="yes"> <source xml:space="preserve">Send to multiple recipients at once</source> <target xml:space="preserve">Send to multiple recipients at once</target> <context-group purpose="location"><context context-type="linenumber">1160</context></context-group> </trans-unit> - <trans-unit id="_msg634" approved="yes"> + <trans-unit id="_msg632" approved="yes"> <source xml:space="preserve">Add &Recipient</source> <target xml:space="preserve">Add &Recipient</target> <context-group purpose="location"><context context-type="linenumber">1163</context></context-group> </trans-unit> - <trans-unit id="_msg635"> + <trans-unit id="_msg633"> <source xml:space="preserve">Clear all fields of the form.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1143</context></context-group> </trans-unit> - <trans-unit id="_msg636"> + <trans-unit id="_msg634"> <source xml:space="preserve">Inputs…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg637"> + <trans-unit id="_msg635"> <source xml:space="preserve">Dust:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">343</context></context-group> </trans-unit> - <trans-unit id="_msg638"> + <trans-unit id="_msg636"> <source xml:space="preserve">Choose…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">741</context></context-group> </trans-unit> - <trans-unit id="_msg639"> + <trans-unit id="_msg637"> <source xml:space="preserve">Hide transaction fee settings</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">800</context></context-group> </trans-unit> - <trans-unit id="_msg640"> + <trans-unit id="_msg638"> <source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">851</context></context-group> </trans-unit> - <trans-unit id="_msg641"> + <trans-unit id="_msg639"> <source xml:space="preserve">When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">886</context></context-group> </trans-unit> - <trans-unit id="_msg642"> + <trans-unit id="_msg640"> <source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">889</context></context-group> </trans-unit> - <trans-unit id="_msg643"> + <trans-unit id="_msg641"> <source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">994</context></context-group> </trans-unit> - <trans-unit id="_msg644"> + <trans-unit id="_msg642"> <source xml:space="preserve">Confirmation time target:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1020</context></context-group> </trans-unit> - <trans-unit id="_msg645"> + <trans-unit id="_msg643"> <source xml:space="preserve">Enable Replace-By-Fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1078</context></context-group> </trans-unit> - <trans-unit id="_msg646"> + <trans-unit id="_msg644"> <source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1081</context></context-group> </trans-unit> - <trans-unit id="_msg647" approved="yes"> + <trans-unit id="_msg645" approved="yes"> <source xml:space="preserve">Clear &All</source> <target xml:space="preserve">Clear &All</target> <context-group purpose="location"><context context-type="linenumber">1146</context></context-group> </trans-unit> - <trans-unit id="_msg648" approved="yes"> + <trans-unit id="_msg646" approved="yes"> <source xml:space="preserve">Balance:</source> <target xml:space="preserve">Balance:</target> <context-group purpose="location"><context context-type="linenumber">1201</context></context-group> </trans-unit> - <trans-unit id="_msg649" approved="yes"> + <trans-unit id="_msg647" approved="yes"> <source xml:space="preserve">Confirm the send action</source> <target xml:space="preserve">Confirm the send action</target> <context-group purpose="location"><context context-type="linenumber">1117</context></context-group> </trans-unit> - <trans-unit id="_msg650" approved="yes"> + <trans-unit id="_msg648" approved="yes"> <source xml:space="preserve">S&end</source> <target xml:space="preserve">S&end</target> <context-group purpose="location"><context context-type="linenumber">1120</context></context-group> @@ -3581,234 +3585,234 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> - <trans-unit id="_msg651"> + <trans-unit id="_msg649"> <source xml:space="preserve">Copy quantity</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">92</context></context-group> </trans-unit> - <trans-unit id="_msg652"> + <trans-unit id="_msg650"> <source xml:space="preserve">Copy amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">93</context></context-group> </trans-unit> - <trans-unit id="_msg653"> + <trans-unit id="_msg651"> <source xml:space="preserve">Copy fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">94</context></context-group> </trans-unit> - <trans-unit id="_msg654"> + <trans-unit id="_msg652"> <source xml:space="preserve">Copy after fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg655"> + <trans-unit id="_msg653"> <source xml:space="preserve">Copy bytes</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg656"> + <trans-unit id="_msg654"> <source xml:space="preserve">Copy dust</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg657"> + <trans-unit id="_msg655"> <source xml:space="preserve">Copy change</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg658"> + <trans-unit id="_msg656"> <source xml:space="preserve">%1 (%2 blocks)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg659"> + <trans-unit id="_msg657"> <source xml:space="preserve">Cr&eate Unsigned</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">203</context></context-group> </trans-unit> - <trans-unit id="_msg660"> + <trans-unit id="_msg658"> <source xml:space="preserve">Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">204</context></context-group> </trans-unit> - <trans-unit id="_msg661"> + <trans-unit id="_msg659"> <source xml:space="preserve"> from wallet '%1'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">294</context></context-group> </trans-unit> - <trans-unit id="_msg662"> + <trans-unit id="_msg660"> <source xml:space="preserve">%1 to '%2'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg663"> + <trans-unit id="_msg661"> <source xml:space="preserve">%1 to %2</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">310</context></context-group> </trans-unit> - <trans-unit id="_msg664"> + <trans-unit id="_msg662"> <source xml:space="preserve">Do you want to draft this transaction?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">317</context></context-group> </trans-unit> - <trans-unit id="_msg665"> + <trans-unit id="_msg663"> <source xml:space="preserve">Are you sure you want to send?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> - <trans-unit id="_msg666"> + <trans-unit id="_msg664"> <source xml:space="preserve">To review recipient list click "Show Details…"</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">371</context></context-group> </trans-unit> - <trans-unit id="_msg667"> + <trans-unit id="_msg665"> <source xml:space="preserve">Create Unsigned</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">390</context></context-group> </trans-unit> - <trans-unit id="_msg668"> + <trans-unit id="_msg666"> <source xml:space="preserve">Save Transaction Data</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">434</context></context-group> </trans-unit> - <trans-unit id="_msg669"> + <trans-unit id="_msg667"> <source xml:space="preserve">Partially Signed Transaction (Binary)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">436</context></context-group> <note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note> </trans-unit> - <trans-unit id="_msg670"> + <trans-unit id="_msg668"> <source xml:space="preserve">PSBT saved</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">443</context></context-group> </trans-unit> - <trans-unit id="_msg671"> + <trans-unit id="_msg669"> <source xml:space="preserve">or</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">367</context></context-group> </trans-unit> - <trans-unit id="_msg672"> + <trans-unit id="_msg670"> <source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">348</context></context-group> </trans-unit> - <trans-unit id="_msg673"> + <trans-unit id="_msg671"> <source xml:space="preserve">Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg674"> + <trans-unit id="_msg672"> <source xml:space="preserve">Please, review your transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg675"> + <trans-unit id="_msg673"> <source xml:space="preserve">Transaction fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">334</context></context-group> </trans-unit> - <trans-unit id="_msg676"> + <trans-unit id="_msg674"> <source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">350</context></context-group> </trans-unit> - <trans-unit id="_msg677"> + <trans-unit id="_msg675"> <source xml:space="preserve">Total Amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">364</context></context-group> </trans-unit> - <trans-unit id="_msg678"> + <trans-unit id="_msg676"> <source xml:space="preserve">Confirm send coins</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">389</context></context-group> </trans-unit> - <trans-unit id="_msg679"> + <trans-unit id="_msg677"> <source xml:space="preserve">Confirm transaction proposal</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">389</context></context-group> </trans-unit> - <trans-unit id="_msg680"> + <trans-unit id="_msg678"> <source xml:space="preserve">Send</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">390</context></context-group> </trans-unit> - <trans-unit id="_msg681"> + <trans-unit id="_msg679"> <source xml:space="preserve">Watch-only balance:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">619</context></context-group> </trans-unit> - <trans-unit id="_msg682"> + <trans-unit id="_msg680"> <source xml:space="preserve">The recipient address is not valid. Please recheck.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">643</context></context-group> </trans-unit> - <trans-unit id="_msg683"> + <trans-unit id="_msg681"> <source xml:space="preserve">The amount to pay must be larger than 0.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">646</context></context-group> </trans-unit> - <trans-unit id="_msg684"> + <trans-unit id="_msg682"> <source xml:space="preserve">The amount exceeds your balance.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">649</context></context-group> </trans-unit> - <trans-unit id="_msg685"> + <trans-unit id="_msg683"> <source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">652</context></context-group> </trans-unit> - <trans-unit id="_msg686"> + <trans-unit id="_msg684"> <source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">655</context></context-group> </trans-unit> - <trans-unit id="_msg687"> + <trans-unit id="_msg685"> <source xml:space="preserve">Transaction creation failed!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">658</context></context-group> </trans-unit> - <trans-unit id="_msg688"> + <trans-unit id="_msg686"> <source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">662</context></context-group> </trans-unit> - <trans-unit id="_msg689"> + <trans-unit id="_msg687"> <source xml:space="preserve">Payment request expired.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">665</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> <context-group purpose="location"><context context-type="linenumber">789</context></context-group> - <trans-unit id="_msg690[0]" approved="yes"> + <trans-unit id="_msg688[0]" approved="yes"> <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> <target xml:space="preserve">Estimated to begin confirmation within %n block.</target> </trans-unit> - <trans-unit id="_msg690[1]" approved="yes"> + <trans-unit id="_msg688[1]" approved="yes"> <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> <target xml:space="preserve">Estimated to begin confirmation within %n blocks.</target> </trans-unit> </group> - <trans-unit id="_msg691"> + <trans-unit id="_msg689"> <source xml:space="preserve">Warning: Invalid Bitcoin address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">890</context></context-group> </trans-unit> - <trans-unit id="_msg692"> + <trans-unit id="_msg690"> <source xml:space="preserve">Warning: Unknown change address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">895</context></context-group> </trans-unit> - <trans-unit id="_msg693"> + <trans-unit id="_msg691"> <source xml:space="preserve">Confirm custom change address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">898</context></context-group> </trans-unit> - <trans-unit id="_msg694"> + <trans-unit id="_msg692"> <source xml:space="preserve">The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">898</context></context-group> </trans-unit> - <trans-unit id="_msg695"> + <trans-unit id="_msg693"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">919</context></context-group> @@ -3817,108 +3821,108 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsEntry"> - <trans-unit id="_msg696" approved="yes"> + <trans-unit id="_msg694" approved="yes"> <source xml:space="preserve">A&mount:</source> <target xml:space="preserve">A&mount:</target> <context-group purpose="location"><context context-type="linenumber">155</context></context-group> <context-group purpose="location"><context context-type="linenumber">705</context></context-group> <context-group purpose="location"><context context-type="linenumber">1238</context></context-group> </trans-unit> - <trans-unit id="_msg697" approved="yes"> + <trans-unit id="_msg695" approved="yes"> <source xml:space="preserve">Pay &To:</source> <target xml:space="preserve">Pay &To:</target> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> </trans-unit> - <trans-unit id="_msg698" approved="yes"> + <trans-unit id="_msg696" approved="yes"> <source xml:space="preserve">&Label:</source> <target xml:space="preserve">&Label:</target> <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> - <trans-unit id="_msg699"> + <trans-unit id="_msg697"> <source xml:space="preserve">Choose previously used address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">64</context></context-group> </trans-unit> - <trans-unit id="_msg700"> + <trans-unit id="_msg698"> <source xml:space="preserve">The Bitcoin address to send the payment to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">57</context></context-group> </trans-unit> - <trans-unit id="_msg701" approved="yes"> + <trans-unit id="_msg699" approved="yes"> <source xml:space="preserve">Alt+A</source> <target xml:space="preserve">Alt+A</target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg702" approved="yes"> + <trans-unit id="_msg700" approved="yes"> <source xml:space="preserve">Paste address from clipboard</source> <target xml:space="preserve">Paste address from clipboard</target> <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> - <trans-unit id="_msg703" approved="yes"> + <trans-unit id="_msg701" approved="yes"> <source xml:space="preserve">Alt+P</source> <target xml:space="preserve">Alt+P</target> <context-group purpose="location"><context context-type="linenumber">103</context></context-group> </trans-unit> - <trans-unit id="_msg704"> + <trans-unit id="_msg702"> <source xml:space="preserve">Remove this entry</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> <context-group purpose="location"><context context-type="linenumber">672</context></context-group> <context-group purpose="location"><context context-type="linenumber">1205</context></context-group> </trans-unit> - <trans-unit id="_msg705"> + <trans-unit id="_msg703"> <source xml:space="preserve">The amount to send in the selected unit</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg706"> + <trans-unit id="_msg704"> <source xml:space="preserve">The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg707"> + <trans-unit id="_msg705"> <source xml:space="preserve">S&ubtract fee from amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg708"> + <trans-unit id="_msg706"> <source xml:space="preserve">Use available balance</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg709"> + <trans-unit id="_msg707"> <source xml:space="preserve">Message:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">196</context></context-group> </trans-unit> - <trans-unit id="_msg710"> + <trans-unit id="_msg708"> <source xml:space="preserve">This is an unauthenticated payment request.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">639</context></context-group> </trans-unit> - <trans-unit id="_msg711"> + <trans-unit id="_msg709"> <source xml:space="preserve">This is an authenticated payment request.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1168</context></context-group> </trans-unit> - <trans-unit id="_msg712"> + <trans-unit id="_msg710"> <source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">145</context></context-group> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg713"> + <trans-unit id="_msg711"> <source xml:space="preserve">A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg714"> + <trans-unit id="_msg712"> <source xml:space="preserve">Pay To:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">654</context></context-group> <context-group purpose="location"><context context-type="linenumber">1183</context></context-group> </trans-unit> - <trans-unit id="_msg715"> + <trans-unit id="_msg713"> <source xml:space="preserve">Memo:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">688</context></context-group> @@ -3928,128 +3932,128 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> - <trans-unit id="_msg716" approved="yes"> + <trans-unit id="_msg714" approved="yes"> <source xml:space="preserve">Signatures - Sign / Verify a Message</source> <target xml:space="preserve">Signatures - Sign / Verify a Message</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg717" approved="yes"> + <trans-unit id="_msg715" approved="yes"> <source xml:space="preserve">&Sign Message</source> <target xml:space="preserve">&Sign Message</target> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg718"> + <trans-unit id="_msg716"> <source xml:space="preserve">You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">33</context></context-group> </trans-unit> - <trans-unit id="_msg719"> + <trans-unit id="_msg717"> <source xml:space="preserve">The Bitcoin address to sign the message with</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg720"> + <trans-unit id="_msg718"> <source xml:space="preserve">Choose previously used address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> <context-group purpose="location"><context context-type="linenumber">274</context></context-group> </trans-unit> - <trans-unit id="_msg721" approved="yes"> + <trans-unit id="_msg719" approved="yes"> <source xml:space="preserve">Alt+A</source> <target xml:space="preserve">Alt+A</target> <context-group purpose="location"><context context-type="linenumber">68</context></context-group> <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> - <trans-unit id="_msg722" approved="yes"> + <trans-unit id="_msg720" approved="yes"> <source xml:space="preserve">Paste address from clipboard</source> <target xml:space="preserve">Paste address from clipboard</target> <context-group purpose="location"><context context-type="linenumber">78</context></context-group> </trans-unit> - <trans-unit id="_msg723" approved="yes"> + <trans-unit id="_msg721" approved="yes"> <source xml:space="preserve">Alt+P</source> <target xml:space="preserve">Alt+P</target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg724" approved="yes"> + <trans-unit id="_msg722" approved="yes"> <source xml:space="preserve">Enter the message you want to sign here</source> <target xml:space="preserve">Enter the message you want to sign here</target> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> <context-group purpose="location"><context context-type="linenumber">103</context></context-group> </trans-unit> - <trans-unit id="_msg725" approved="yes"> + <trans-unit id="_msg723" approved="yes"> <source xml:space="preserve">Signature</source> <target xml:space="preserve">Signature</target> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg726" approved="yes"> + <trans-unit id="_msg724" approved="yes"> <source xml:space="preserve">Copy the current signature to the system clipboard</source> <target xml:space="preserve">Copy the current signature to the system clipboard</target> <context-group purpose="location"><context context-type="linenumber">140</context></context-group> </trans-unit> - <trans-unit id="_msg727" approved="yes"> + <trans-unit id="_msg725" approved="yes"> <source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source> <target xml:space="preserve">Sign the message to prove you own this Bitcoin address</target> <context-group purpose="location"><context context-type="linenumber">161</context></context-group> </trans-unit> - <trans-unit id="_msg728" approved="yes"> + <trans-unit id="_msg726" approved="yes"> <source xml:space="preserve">Sign &Message</source> <target xml:space="preserve">Sign &Message</target> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg729" approved="yes"> + <trans-unit id="_msg727" approved="yes"> <source xml:space="preserve">Reset all sign message fields</source> <target xml:space="preserve">Reset all sign message fields</target> <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg730" approved="yes"> + <trans-unit id="_msg728" approved="yes"> <source xml:space="preserve">Clear &All</source> <target xml:space="preserve">Clear &All</target> <context-group purpose="location"><context context-type="linenumber">181</context></context-group> <context-group purpose="location"><context context-type="linenumber">338</context></context-group> </trans-unit> - <trans-unit id="_msg731" approved="yes"> + <trans-unit id="_msg729" approved="yes"> <source xml:space="preserve">&Verify Message</source> <target xml:space="preserve">&Verify Message</target> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg732"> + <trans-unit id="_msg730"> <source xml:space="preserve">Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg733"> + <trans-unit id="_msg731"> <source xml:space="preserve">The Bitcoin address the message was signed with</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">267</context></context-group> </trans-unit> - <trans-unit id="_msg734"> + <trans-unit id="_msg732"> <source xml:space="preserve">The signed message to verify</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">296</context></context-group> <context-group purpose="location"><context context-type="linenumber">299</context></context-group> </trans-unit> - <trans-unit id="_msg735"> + <trans-unit id="_msg733"> <source xml:space="preserve">The signature given when the message was signed</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">306</context></context-group> <context-group purpose="location"><context context-type="linenumber">309</context></context-group> </trans-unit> - <trans-unit id="_msg736" approved="yes"> + <trans-unit id="_msg734" approved="yes"> <source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source> <target xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</target> <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg737" approved="yes"> + <trans-unit id="_msg735" approved="yes"> <source xml:space="preserve">Verify &Message</source> <target xml:space="preserve">Verify &Message</target> <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg738" approved="yes"> + <trans-unit id="_msg736" approved="yes"> <source xml:space="preserve">Reset all verify message fields</source> <target xml:space="preserve">Reset all verify message fields</target> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg739"> + <trans-unit id="_msg737"> <source xml:space="preserve">Click "Sign Message" to generate signature</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">125</context></context-group> @@ -4058,13 +4062,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> - <trans-unit id="_msg740"> + <trans-unit id="_msg738"> <source xml:space="preserve">The entered address is invalid.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> <context-group purpose="location"><context context-type="linenumber">219</context></context-group> </trans-unit> - <trans-unit id="_msg741"> + <trans-unit id="_msg739"> <source xml:space="preserve">Please check the address and try again.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> @@ -4072,59 +4076,59 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context-group purpose="location"><context context-type="linenumber">220</context></context-group> <context-group purpose="location"><context context-type="linenumber">227</context></context-group> </trans-unit> - <trans-unit id="_msg742"> + <trans-unit id="_msg740"> <source xml:space="preserve">The entered address does not refer to a key.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">127</context></context-group> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg743"> + <trans-unit id="_msg741"> <source xml:space="preserve">Wallet unlock was cancelled.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">135</context></context-group> </trans-unit> - <trans-unit id="_msg744"> + <trans-unit id="_msg742"> <source xml:space="preserve">No error</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg745"> + <trans-unit id="_msg743"> <source xml:space="preserve">Private key for the entered address is not available.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">149</context></context-group> </trans-unit> - <trans-unit id="_msg746"> + <trans-unit id="_msg744"> <source xml:space="preserve">Message signing failed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg747"> + <trans-unit id="_msg745"> <source xml:space="preserve">Message signed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg748"> + <trans-unit id="_msg746"> <source xml:space="preserve">The signature could not be decoded.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">233</context></context-group> </trans-unit> - <trans-unit id="_msg749"> + <trans-unit id="_msg747"> <source xml:space="preserve">Please check the signature and try again.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">234</context></context-group> <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg750"> + <trans-unit id="_msg748"> <source xml:space="preserve">The signature did not match the message digest.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg751"> + <trans-unit id="_msg749"> <source xml:space="preserve">Message verification failed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg752"> + <trans-unit id="_msg750"> <source xml:space="preserve">Message verified.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">214</context></context-group> @@ -4133,7 +4137,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget"> - <trans-unit id="_msg753"> + <trans-unit id="_msg751"> <source xml:space="preserve">kB/s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">82</context></context-group> @@ -4144,111 +4148,111 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <group restype="x-trolltech-linguist-context" resname="TransactionDesc"> <group restype="x-gettext-plurals"> <context-group purpose="location"><context context-type="linenumber">36</context></context-group> - <trans-unit id="_msg754[0]" approved="yes"> + <trans-unit id="_msg752[0]" approved="yes"> <source xml:space="preserve">Open for %n more block(s)</source> <target xml:space="preserve">Open for %n more block</target> </trans-unit> - <trans-unit id="_msg754[1]" approved="yes"> + <trans-unit id="_msg752[1]" approved="yes"> <source xml:space="preserve">Open for %n more block(s)</source> <target xml:space="preserve">Open for %n more blocks</target> </trans-unit> </group> - <trans-unit id="_msg755"> + <trans-unit id="_msg753"> <source xml:space="preserve">Open until %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">38</context></context-group> </trans-unit> - <trans-unit id="_msg756"> + <trans-unit id="_msg754"> <source xml:space="preserve">conflicted with a transaction with %1 confirmations</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">44</context></context-group> </trans-unit> - <trans-unit id="_msg757"> + <trans-unit id="_msg755"> <source xml:space="preserve">0/unconfirmed, %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg758"> + <trans-unit id="_msg756"> <source xml:space="preserve">in memory pool</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg759"> + <trans-unit id="_msg757"> <source xml:space="preserve">not in memory pool</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg760"> + <trans-unit id="_msg758"> <source xml:space="preserve">abandoned</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">46</context></context-group> </trans-unit> - <trans-unit id="_msg761"> + <trans-unit id="_msg759"> <source xml:space="preserve">%1/unconfirmed</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg762"> + <trans-unit id="_msg760"> <source xml:space="preserve">%1 confirmations</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg763"> + <trans-unit id="_msg761"> <source xml:space="preserve">Status</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg764"> + <trans-unit id="_msg762"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">105</context></context-group> </trans-unit> - <trans-unit id="_msg765"> + <trans-unit id="_msg763"> <source xml:space="preserve">Source</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">112</context></context-group> </trans-unit> - <trans-unit id="_msg766"> + <trans-unit id="_msg764"> <source xml:space="preserve">Generated</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">112</context></context-group> </trans-unit> - <trans-unit id="_msg767"> + <trans-unit id="_msg765"> <source xml:space="preserve">From</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">117</context></context-group> <context-group purpose="location"><context context-type="linenumber">131</context></context-group> <context-group purpose="location"><context context-type="linenumber">203</context></context-group> </trans-unit> - <trans-unit id="_msg768"> + <trans-unit id="_msg766"> <source xml:space="preserve">unknown</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> - <trans-unit id="_msg769"> + <trans-unit id="_msg767"> <source xml:space="preserve">To</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">132</context></context-group> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg770"> + <trans-unit id="_msg768"> <source xml:space="preserve">own address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">134</context></context-group> </trans-unit> - <trans-unit id="_msg771"> + <trans-unit id="_msg769"> <source xml:space="preserve">watch-only</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">134</context></context-group> <context-group purpose="location"><context context-type="linenumber">203</context></context-group> </trans-unit> - <trans-unit id="_msg772"> + <trans-unit id="_msg770"> <source xml:space="preserve">label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">136</context></context-group> </trans-unit> - <trans-unit id="_msg773"> + <trans-unit id="_msg771"> <source xml:space="preserve">Credit</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> @@ -4259,120 +4263,120 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </trans-unit> <group restype="x-gettext-plurals"> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> - <trans-unit id="_msg774[0]" approved="yes"> + <trans-unit id="_msg772[0]" approved="yes"> <source xml:space="preserve">matures in %n more block(s)</source> <target xml:space="preserve">matures in %n more block</target> </trans-unit> - <trans-unit id="_msg774[1]" approved="yes"> + <trans-unit id="_msg772[1]" approved="yes"> <source xml:space="preserve">matures in %n more block(s)</source> <target xml:space="preserve">matures in %n more blocks</target> </trans-unit> </group> - <trans-unit id="_msg775"> + <trans-unit id="_msg773"> <source xml:space="preserve">not accepted</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg776"> + <trans-unit id="_msg774"> <source xml:space="preserve">Debit</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">236</context></context-group> <context-group purpose="location"><context context-type="linenumber">262</context></context-group> <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg777"> + <trans-unit id="_msg775"> <source xml:space="preserve">Total debit</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg778"> + <trans-unit id="_msg776"> <source xml:space="preserve">Total credit</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">247</context></context-group> </trans-unit> - <trans-unit id="_msg779"> + <trans-unit id="_msg777"> <source xml:space="preserve">Transaction fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">252</context></context-group> </trans-unit> - <trans-unit id="_msg780"> + <trans-unit id="_msg778"> <source xml:space="preserve">Net amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">274</context></context-group> </trans-unit> - <trans-unit id="_msg781"> + <trans-unit id="_msg779"> <source xml:space="preserve">Message</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">280</context></context-group> <context-group purpose="location"><context context-type="linenumber">292</context></context-group> </trans-unit> - <trans-unit id="_msg782"> + <trans-unit id="_msg780"> <source xml:space="preserve">Comment</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">282</context></context-group> </trans-unit> - <trans-unit id="_msg783"> + <trans-unit id="_msg781"> <source xml:space="preserve">Transaction ID</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> - <trans-unit id="_msg784"> + <trans-unit id="_msg782"> <source xml:space="preserve">Transaction total size</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> - <trans-unit id="_msg785"> + <trans-unit id="_msg783"> <source xml:space="preserve">Transaction virtual size</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">286</context></context-group> </trans-unit> - <trans-unit id="_msg786"> + <trans-unit id="_msg784"> <source xml:space="preserve">Output index</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">287</context></context-group> </trans-unit> - <trans-unit id="_msg787"> + <trans-unit id="_msg785"> <source xml:space="preserve"> (Certificate was not verified)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> - <trans-unit id="_msg788"> + <trans-unit id="_msg786"> <source xml:space="preserve">Merchant</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> - <trans-unit id="_msg789"> + <trans-unit id="_msg787"> <source xml:space="preserve">Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> - <trans-unit id="_msg790"> + <trans-unit id="_msg788"> <source xml:space="preserve">Debug information</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg791"> + <trans-unit id="_msg789"> <source xml:space="preserve">Transaction</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">330</context></context-group> </trans-unit> - <trans-unit id="_msg792"> + <trans-unit id="_msg790"> <source xml:space="preserve">Inputs</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">333</context></context-group> </trans-unit> - <trans-unit id="_msg793"> + <trans-unit id="_msg791"> <source xml:space="preserve">Amount</source> <target xml:space="preserve" state="needs-review-translation">Amount</target> <context-group purpose="location"><context context-type="linenumber">354</context></context-group> </trans-unit> - <trans-unit id="_msg794"> + <trans-unit id="_msg792"> <source xml:space="preserve">true</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">355</context></context-group> <context-group purpose="location"><context context-type="linenumber">356</context></context-group> </trans-unit> - <trans-unit id="_msg795"> + <trans-unit id="_msg793"> <source xml:space="preserve">false</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">355</context></context-group> @@ -4382,7 +4386,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> - <trans-unit id="_msg796" approved="yes"> + <trans-unit id="_msg794" approved="yes"> <source xml:space="preserve">This pane shows a detailed description of the transaction</source> <target xml:space="preserve">This pane shows a detailed description of the transaction</target> <context-group purpose="location"><context context-type="linenumber">20</context></context-group> @@ -4391,7 +4395,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> - <trans-unit id="_msg797"> + <trans-unit id="_msg795"> <source xml:space="preserve">Details for %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">18</context></context-group> @@ -4400,138 +4404,138 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionTableModel"> - <trans-unit id="_msg798"> + <trans-unit id="_msg796"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg799"> + <trans-unit id="_msg797"> <source xml:space="preserve">Type</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg800"> + <trans-unit id="_msg798"> <source xml:space="preserve">Label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> <context-group purpose="location"><context context-type="linenumber">320</context></context-group> - <trans-unit id="_msg801[0]" approved="yes"> + <trans-unit id="_msg799[0]" approved="yes"> <source xml:space="preserve">Open for %n more block(s)</source> <target xml:space="preserve">Open for %n more block</target> </trans-unit> - <trans-unit id="_msg801[1]" approved="yes"> + <trans-unit id="_msg799[1]" approved="yes"> <source xml:space="preserve">Open for %n more block(s)</source> <target xml:space="preserve">Open for %n more blocks</target> </trans-unit> </group> - <trans-unit id="_msg802"> + <trans-unit id="_msg800"> <source xml:space="preserve">Open until %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg803"> + <trans-unit id="_msg801"> <source xml:space="preserve">Unconfirmed</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg804"> + <trans-unit id="_msg802"> <source xml:space="preserve">Abandoned</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">329</context></context-group> </trans-unit> - <trans-unit id="_msg805"> + <trans-unit id="_msg803"> <source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">332</context></context-group> </trans-unit> - <trans-unit id="_msg806"> + <trans-unit id="_msg804"> <source xml:space="preserve">Confirmed (%1 confirmations)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg807"> + <trans-unit id="_msg805"> <source xml:space="preserve">Conflicted</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">338</context></context-group> </trans-unit> - <trans-unit id="_msg808"> + <trans-unit id="_msg806"> <source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">341</context></context-group> </trans-unit> - <trans-unit id="_msg809"> + <trans-unit id="_msg807"> <source xml:space="preserve">Generated but not accepted</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> - <trans-unit id="_msg810"> + <trans-unit id="_msg808"> <source xml:space="preserve">Received with</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">383</context></context-group> </trans-unit> - <trans-unit id="_msg811"> + <trans-unit id="_msg809"> <source xml:space="preserve">Received from</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">385</context></context-group> </trans-unit> - <trans-unit id="_msg812"> + <trans-unit id="_msg810"> <source xml:space="preserve">Sent to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">388</context></context-group> </trans-unit> - <trans-unit id="_msg813"> + <trans-unit id="_msg811"> <source xml:space="preserve">Payment to yourself</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">390</context></context-group> </trans-unit> - <trans-unit id="_msg814"> + <trans-unit id="_msg812"> <source xml:space="preserve">Mined</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> - <trans-unit id="_msg815"> + <trans-unit id="_msg813"> <source xml:space="preserve">watch-only</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">420</context></context-group> </trans-unit> - <trans-unit id="_msg816"> + <trans-unit id="_msg814"> <source xml:space="preserve">(n/a)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">436</context></context-group> </trans-unit> - <trans-unit id="_msg817"> + <trans-unit id="_msg815"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">646</context></context-group> </trans-unit> - <trans-unit id="_msg818"> + <trans-unit id="_msg816"> <source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">685</context></context-group> </trans-unit> - <trans-unit id="_msg819"> + <trans-unit id="_msg817"> <source xml:space="preserve">Date and time that the transaction was received.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">687</context></context-group> </trans-unit> - <trans-unit id="_msg820"> + <trans-unit id="_msg818"> <source xml:space="preserve">Type of transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">689</context></context-group> </trans-unit> - <trans-unit id="_msg821"> + <trans-unit id="_msg819"> <source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">691</context></context-group> </trans-unit> - <trans-unit id="_msg822"> + <trans-unit id="_msg820"> <source xml:space="preserve">User-defined intent/purpose of the transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">693</context></context-group> </trans-unit> - <trans-unit id="_msg823"> + <trans-unit id="_msg821"> <source xml:space="preserve">Amount removed from or added to balance.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">695</context></context-group> @@ -4540,215 +4544,215 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactionview.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionView"> - <trans-unit id="_msg824"> + <trans-unit id="_msg822"> <source xml:space="preserve">All</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">70</context></context-group> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> - <trans-unit id="_msg825"> + <trans-unit id="_msg823"> <source xml:space="preserve">Today</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg826"> + <trans-unit id="_msg824"> <source xml:space="preserve">This week</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">72</context></context-group> </trans-unit> - <trans-unit id="_msg827"> + <trans-unit id="_msg825"> <source xml:space="preserve">This month</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg828"> + <trans-unit id="_msg826"> <source xml:space="preserve">Last month</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> - <trans-unit id="_msg829"> + <trans-unit id="_msg827"> <source xml:space="preserve">This year</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">75</context></context-group> </trans-unit> - <trans-unit id="_msg830"> + <trans-unit id="_msg828"> <source xml:space="preserve">Received with</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> - <trans-unit id="_msg831"> + <trans-unit id="_msg829"> <source xml:space="preserve">Sent to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">89</context></context-group> </trans-unit> - <trans-unit id="_msg832"> + <trans-unit id="_msg830"> <source xml:space="preserve">To yourself</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">91</context></context-group> </trans-unit> - <trans-unit id="_msg833"> + <trans-unit id="_msg831"> <source xml:space="preserve">Mined</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">92</context></context-group> </trans-unit> - <trans-unit id="_msg834"> + <trans-unit id="_msg832"> <source xml:space="preserve">Other</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">93</context></context-group> </trans-unit> - <trans-unit id="_msg835"> + <trans-unit id="_msg833"> <source xml:space="preserve">Enter address, transaction id, or label to search</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg836"> + <trans-unit id="_msg834"> <source xml:space="preserve">Min amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg837"> + <trans-unit id="_msg835"> <source xml:space="preserve">Abandon transaction</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg838"> + <trans-unit id="_msg836"> <source xml:space="preserve">Increase transaction fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg839"> + <trans-unit id="_msg837"> <source xml:space="preserve">Copy address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">166</context></context-group> </trans-unit> - <trans-unit id="_msg840"> + <trans-unit id="_msg838"> <source xml:space="preserve">Copy label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">167</context></context-group> </trans-unit> - <trans-unit id="_msg841"> + <trans-unit id="_msg839"> <source xml:space="preserve">Copy amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">168</context></context-group> </trans-unit> - <trans-unit id="_msg842"> + <trans-unit id="_msg840"> <source xml:space="preserve">Copy transaction ID</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">169</context></context-group> </trans-unit> - <trans-unit id="_msg843"> + <trans-unit id="_msg841"> <source xml:space="preserve">Copy raw transaction</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg844"> + <trans-unit id="_msg842"> <source xml:space="preserve">Copy full transaction details</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">171</context></context-group> </trans-unit> - <trans-unit id="_msg845"> + <trans-unit id="_msg843"> <source xml:space="preserve">Edit address label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg846"> + <trans-unit id="_msg844"> <source xml:space="preserve">Show transaction details</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg847"> + <trans-unit id="_msg845"> <source xml:space="preserve">Range…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg848"> + <trans-unit id="_msg846"> <source xml:space="preserve">Export Transaction History</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> </trans-unit> - <trans-unit id="_msg849"> + <trans-unit id="_msg847"> <source xml:space="preserve">Comma separated file</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + <context-group purpose="location"><context context-type="linenumber">355</context></context-group> <note annotates="source" from="developer">Expanded name of the CSV file format. See https://en.wikipedia.org/wiki/Comma-separated_values</note> </trans-unit> - <trans-unit id="_msg850"> + <trans-unit id="_msg848"> <source xml:space="preserve">Confirmed</source> <target xml:space="preserve" state="needs-review-translation">Confirmed</target> - <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + <context-group purpose="location"><context context-type="linenumber">364</context></context-group> </trans-unit> - <trans-unit id="_msg851"> + <trans-unit id="_msg849"> <source xml:space="preserve">Watch-only</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + <context-group purpose="location"><context context-type="linenumber">366</context></context-group> </trans-unit> - <trans-unit id="_msg852"> + <trans-unit id="_msg850"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> - <context-group purpose="location"><context context-type="linenumber">353</context></context-group> + <context-group purpose="location"><context context-type="linenumber">367</context></context-group> </trans-unit> - <trans-unit id="_msg853"> + <trans-unit id="_msg851"> <source xml:space="preserve">Type</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + <context-group purpose="location"><context context-type="linenumber">368</context></context-group> </trans-unit> - <trans-unit id="_msg854"> + <trans-unit id="_msg852"> <source xml:space="preserve">Label</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">355</context></context-group> + <context-group purpose="location"><context context-type="linenumber">369</context></context-group> </trans-unit> - <trans-unit id="_msg855"> + <trans-unit id="_msg853"> <source xml:space="preserve">Address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">370</context></context-group> </trans-unit> - <trans-unit id="_msg856"> + <trans-unit id="_msg854"> <source xml:space="preserve">ID</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">358</context></context-group> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> </trans-unit> - <trans-unit id="_msg857"> + <trans-unit id="_msg855"> <source xml:space="preserve">Exporting Failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">375</context></context-group> </trans-unit> - <trans-unit id="_msg858"> + <trans-unit id="_msg856"> <source xml:space="preserve">There was an error trying to save the transaction history to %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">375</context></context-group> </trans-unit> - <trans-unit id="_msg859"> + <trans-unit id="_msg857"> <source xml:space="preserve">Exporting Successful</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + <context-group purpose="location"><context context-type="linenumber">379</context></context-group> </trans-unit> - <trans-unit id="_msg860"> + <trans-unit id="_msg858"> <source xml:space="preserve">The transaction history was successfully saved to %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + <context-group purpose="location"><context context-type="linenumber">379</context></context-group> </trans-unit> - <trans-unit id="_msg861"> + <trans-unit id="_msg859"> <source xml:space="preserve">Range:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">537</context></context-group> + <context-group purpose="location"><context context-type="linenumber">551</context></context-group> </trans-unit> - <trans-unit id="_msg862"> + <trans-unit id="_msg860"> <source xml:space="preserve">to</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">545</context></context-group> + <context-group purpose="location"><context context-type="linenumber">559</context></context-group> </trans-unit> </group> </body></file> <file original="../walletframe.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletFrame"> - <trans-unit id="_msg863"> + <trans-unit id="_msg861"> <source xml:space="preserve">No wallet has been loaded. Go to File > Open Wallet to load a wallet. - OR -</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> </trans-unit> - <trans-unit id="_msg864"> + <trans-unit id="_msg862"> <source xml:space="preserve">Create a new wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">44</context></context-group> @@ -4757,12 +4761,12 @@ Go to File > Open Wallet to load a wallet. </body></file> <file original="../walletmodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletModel"> - <trans-unit id="_msg865"> + <trans-unit id="_msg863"> <source xml:space="preserve">Send Coins</source> <target xml:space="preserve" state="needs-review-translation">Send Coins</target> <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> - <trans-unit id="_msg866"> + <trans-unit id="_msg864"> <source xml:space="preserve">Fee bump error</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">497</context></context-group> @@ -4770,67 +4774,67 @@ Go to File > Open Wallet to load a wallet. <context-group purpose="location"><context context-type="linenumber">562</context></context-group> <context-group purpose="location"><context context-type="linenumber">567</context></context-group> </trans-unit> - <trans-unit id="_msg867"> + <trans-unit id="_msg865"> <source xml:space="preserve">Increasing transaction fee failed</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">497</context></context-group> </trans-unit> - <trans-unit id="_msg868"> + <trans-unit id="_msg866"> <source xml:space="preserve">Do you want to increase the fee?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">505</context></context-group> </trans-unit> - <trans-unit id="_msg869"> + <trans-unit id="_msg867"> <source xml:space="preserve">Do you want to draft a transaction with fee increase?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">505</context></context-group> </trans-unit> - <trans-unit id="_msg870"> + <trans-unit id="_msg868"> <source xml:space="preserve">Current fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">509</context></context-group> </trans-unit> - <trans-unit id="_msg871"> + <trans-unit id="_msg869"> <source xml:space="preserve">Increase:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">513</context></context-group> </trans-unit> - <trans-unit id="_msg872"> + <trans-unit id="_msg870"> <source xml:space="preserve">New fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">517</context></context-group> </trans-unit> - <trans-unit id="_msg873"> + <trans-unit id="_msg871"> <source xml:space="preserve">Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">525</context></context-group> </trans-unit> - <trans-unit id="_msg874"> + <trans-unit id="_msg872"> <source xml:space="preserve">Confirm fee bump</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">528</context></context-group> </trans-unit> - <trans-unit id="_msg875"> + <trans-unit id="_msg873"> <source xml:space="preserve">Can't draft transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">549</context></context-group> </trans-unit> - <trans-unit id="_msg876"> + <trans-unit id="_msg874"> <source xml:space="preserve">PSBT copied</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">556</context></context-group> </trans-unit> - <trans-unit id="_msg877"> + <trans-unit id="_msg875"> <source xml:space="preserve">Can't sign transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">562</context></context-group> </trans-unit> - <trans-unit id="_msg878"> + <trans-unit id="_msg876"> <source xml:space="preserve">Could not commit transaction</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">567</context></context-group> </trans-unit> - <trans-unit id="_msg879"> + <trans-unit id="_msg877"> <source xml:space="preserve">default wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">587</context></context-group> @@ -4839,80 +4843,80 @@ Go to File > Open Wallet to load a wallet. </body></file> <file original="../walletview.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletView"> - <trans-unit id="_msg880"> + <trans-unit id="_msg878"> <source xml:space="preserve">&Export</source> <target xml:space="preserve" state="needs-review-translation">&Export</target> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg881"> + <trans-unit id="_msg879"> <source xml:space="preserve">Export the data in the current tab to a file</source> <target xml:space="preserve" state="needs-review-translation">Export the data in the current tab to a file</target> <context-group purpose="location"><context context-type="linenumber">52</context></context-group> </trans-unit> - <trans-unit id="_msg882"> + <trans-unit id="_msg880"> <source xml:space="preserve">Error</source> <target xml:space="preserve" state="needs-review-translation">Error</target> <context-group purpose="location"><context context-type="linenumber">217</context></context-group> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> <context-group purpose="location"><context context-type="linenumber">236</context></context-group> </trans-unit> - <trans-unit id="_msg883"> + <trans-unit id="_msg881"> <source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">217</context></context-group> </trans-unit> - <trans-unit id="_msg884"> + <trans-unit id="_msg882"> <source xml:space="preserve">Load Transaction Data</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg885"> + <trans-unit id="_msg883"> <source xml:space="preserve">Partially Signed Transaction (*.psbt)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">223</context></context-group> </trans-unit> - <trans-unit id="_msg886"> + <trans-unit id="_msg884"> <source xml:space="preserve">PSBT file must be smaller than 100 MiB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg887"> + <trans-unit id="_msg885"> <source xml:space="preserve">Unable to decode PSBT</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">236</context></context-group> </trans-unit> - <trans-unit id="_msg888"> + <trans-unit id="_msg886"> <source xml:space="preserve">Backup Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> - <trans-unit id="_msg889"> + <trans-unit id="_msg887"> <source xml:space="preserve">Wallet Data</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">277</context></context-group> <note annotates="source" from="developer">Name of the wallet data file format.</note> </trans-unit> - <trans-unit id="_msg890"> + <trans-unit id="_msg888"> <source xml:space="preserve">Backup Failed</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> - <trans-unit id="_msg891"> + <trans-unit id="_msg889"> <source xml:space="preserve">There was an error trying to save the wallet data to %1.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> - <trans-unit id="_msg892"> + <trans-unit id="_msg890"> <source xml:space="preserve">Backup Successful</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">287</context></context-group> </trans-unit> - <trans-unit id="_msg893"> + <trans-unit id="_msg891"> <source xml:space="preserve">The wallet data was successfully saved to %1.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">287</context></context-group> </trans-unit> - <trans-unit id="_msg894"> + <trans-unit id="_msg892"> <source xml:space="preserve">Cancel</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">331</context></context-group> @@ -4921,762 +4925,762 @@ Go to File > Open Wallet to load a wallet. </body></file> <file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="bitcoin-core"> - <trans-unit id="_msg895"> + <trans-unit id="_msg893"> <source xml:space="preserve">The %s developers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">12</context></context-group> </trans-unit> - <trans-unit id="_msg896"> + <trans-unit id="_msg894"> <source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">13</context></context-group> </trans-unit> - <trans-unit id="_msg897"> + <trans-unit id="_msg895"> <source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">16</context></context-group> </trans-unit> - <trans-unit id="_msg898"> + <trans-unit id="_msg896"> <source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">19</context></context-group> </trans-unit> - <trans-unit id="_msg899"> + <trans-unit id="_msg897"> <source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">22</context></context-group> </trans-unit> - <trans-unit id="_msg900"> + <trans-unit id="_msg898"> <source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">24</context></context-group> </trans-unit> - <trans-unit id="_msg901"> + <trans-unit id="_msg899"> <source xml:space="preserve">Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg902"> + <trans-unit id="_msg900"> <source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">31</context></context-group> </trans-unit> - <trans-unit id="_msg903"> + <trans-unit id="_msg901"> <source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg904"> + <trans-unit id="_msg902"> <source xml:space="preserve">Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg905"> + <trans-unit id="_msg903"> <source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> </trans-unit> - <trans-unit id="_msg906"> + <trans-unit id="_msg904"> <source xml:space="preserve">Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">41</context></context-group> </trans-unit> - <trans-unit id="_msg907"> + <trans-unit id="_msg905"> <source xml:space="preserve">Error: Listening for incoming connections failed (listen returned error %s)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">44</context></context-group> </trans-unit> - <trans-unit id="_msg908"> + <trans-unit id="_msg906"> <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">46</context></context-group> </trans-unit> - <trans-unit id="_msg909"> + <trans-unit id="_msg907"> <source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg910"> + <trans-unit id="_msg908"> <source xml:space="preserve">Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">52</context></context-group> </trans-unit> - <trans-unit id="_msg911"> + <trans-unit id="_msg909"> <source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">55</context></context-group> </trans-unit> - <trans-unit id="_msg912"> + <trans-unit id="_msg910"> <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg913"> + <trans-unit id="_msg911"> <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">61</context></context-group> </trans-unit> - <trans-unit id="_msg914"> + <trans-unit id="_msg912"> <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">63</context></context-group> </trans-unit> - <trans-unit id="_msg915"> + <trans-unit id="_msg913"> <source xml:space="preserve">Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg916"> + <trans-unit id="_msg914"> <source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">69</context></context-group> </trans-unit> - <trans-unit id="_msg917"> + <trans-unit id="_msg915"> <source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">72</context></context-group> </trans-unit> - <trans-unit id="_msg918"> + <trans-unit id="_msg916"> <source xml:space="preserve">Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> - <trans-unit id="_msg919"> + <trans-unit id="_msg917"> <source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">77</context></context-group> </trans-unit> - <trans-unit id="_msg920"> + <trans-unit id="_msg918"> <source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg921"> + <trans-unit id="_msg919"> <source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> - <trans-unit id="_msg922"> + <trans-unit id="_msg920"> <source xml:space="preserve">This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> - <trans-unit id="_msg923"> + <trans-unit id="_msg921"> <source xml:space="preserve">This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">91</context></context-group> </trans-unit> - <trans-unit id="_msg924"> + <trans-unit id="_msg922"> <source xml:space="preserve">This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">94</context></context-group> </trans-unit> - <trans-unit id="_msg925"> + <trans-unit id="_msg923"> <source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg926"> + <trans-unit id="_msg924"> <source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg927"> + <trans-unit id="_msg925"> <source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg928"> + <trans-unit id="_msg926"> <source xml:space="preserve">Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">105</context></context-group> </trans-unit> - <trans-unit id="_msg929"> + <trans-unit id="_msg927"> <source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg930"> + <trans-unit id="_msg928"> <source xml:space="preserve">Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg931"> + <trans-unit id="_msg929"> <source xml:space="preserve">Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">114</context></context-group> </trans-unit> - <trans-unit id="_msg932"> + <trans-unit id="_msg930"> <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">117</context></context-group> </trans-unit> - <trans-unit id="_msg933"> + <trans-unit id="_msg931"> <source xml:space="preserve">Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">119</context></context-group> </trans-unit> - <trans-unit id="_msg934"> + <trans-unit id="_msg932"> <source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg935"> + <trans-unit id="_msg933"> <source xml:space="preserve">You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">125</context></context-group> </trans-unit> - <trans-unit id="_msg936"> + <trans-unit id="_msg934"> <source xml:space="preserve">%s is set very high!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">128</context></context-group> </trans-unit> - <trans-unit id="_msg937"> + <trans-unit id="_msg935"> <source xml:space="preserve">-maxmempool must be at least %d MB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">129</context></context-group> </trans-unit> - <trans-unit id="_msg938"> + <trans-unit id="_msg936"> <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">130</context></context-group> </trans-unit> - <trans-unit id="_msg939"> + <trans-unit id="_msg937"> <source xml:space="preserve">Cannot resolve -%s address: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> - <trans-unit id="_msg940"> + <trans-unit id="_msg938"> <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> - <trans-unit id="_msg941"> + <trans-unit id="_msg939"> <source xml:space="preserve">Cannot write to data directory '%s'; check permissions.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">133</context></context-group> </trans-unit> - <trans-unit id="_msg942"> + <trans-unit id="_msg940"> <source xml:space="preserve">Change index out of range</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">134</context></context-group> </trans-unit> - <trans-unit id="_msg943"> + <trans-unit id="_msg941"> <source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">135</context></context-group> </trans-unit> - <trans-unit id="_msg944"> + <trans-unit id="_msg942"> <source xml:space="preserve">Copyright (C) %i-%i</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">136</context></context-group> </trans-unit> - <trans-unit id="_msg945"> + <trans-unit id="_msg943"> <source xml:space="preserve">Corrupted block database detected</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg946"> + <trans-unit id="_msg944"> <source xml:space="preserve">Could not find asmap file %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg947"> + <trans-unit id="_msg945"> <source xml:space="preserve">Could not parse asmap file %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg948"> + <trans-unit id="_msg946"> <source xml:space="preserve">Disk space is too low!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">140</context></context-group> </trans-unit> - <trans-unit id="_msg949"> + <trans-unit id="_msg947"> <source xml:space="preserve">Do you want to rebuild the block database now?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">141</context></context-group> </trans-unit> - <trans-unit id="_msg950"> + <trans-unit id="_msg948"> <source xml:space="preserve">Done loading</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">142</context></context-group> </trans-unit> - <trans-unit id="_msg951"> + <trans-unit id="_msg949"> <source xml:space="preserve">Dump file %s does not exist.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">143</context></context-group> </trans-unit> - <trans-unit id="_msg952"> + <trans-unit id="_msg950"> <source xml:space="preserve">Error creating %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">144</context></context-group> </trans-unit> - <trans-unit id="_msg953"> + <trans-unit id="_msg951"> <source xml:space="preserve">Error initializing block database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> - <trans-unit id="_msg954"> + <trans-unit id="_msg952"> <source xml:space="preserve">Error initializing wallet database environment %s!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg955"> + <trans-unit id="_msg953"> <source xml:space="preserve">Error loading %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">147</context></context-group> </trans-unit> - <trans-unit id="_msg956"> + <trans-unit id="_msg954"> <source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg957"> + <trans-unit id="_msg955"> <source xml:space="preserve">Error loading %s: Wallet corrupted</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">149</context></context-group> </trans-unit> - <trans-unit id="_msg958"> + <trans-unit id="_msg956"> <source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">150</context></context-group> </trans-unit> - <trans-unit id="_msg959"> + <trans-unit id="_msg957"> <source xml:space="preserve">Error loading block database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">151</context></context-group> </trans-unit> - <trans-unit id="_msg960"> + <trans-unit id="_msg958"> <source xml:space="preserve">Error opening block database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg961"> + <trans-unit id="_msg959"> <source xml:space="preserve">Error reading from database, shutting down.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">153</context></context-group> </trans-unit> - <trans-unit id="_msg962"> + <trans-unit id="_msg960"> <source xml:space="preserve">Error reading next record from wallet database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">154</context></context-group> </trans-unit> - <trans-unit id="_msg963"> + <trans-unit id="_msg961"> <source xml:space="preserve">Error upgrading chainstate database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">155</context></context-group> </trans-unit> - <trans-unit id="_msg964"> + <trans-unit id="_msg962"> <source xml:space="preserve">Error: Couldn't create cursor into database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">156</context></context-group> </trans-unit> - <trans-unit id="_msg965"> + <trans-unit id="_msg963"> <source xml:space="preserve">Error: Disk space is low for %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">157</context></context-group> </trans-unit> - <trans-unit id="_msg966"> + <trans-unit id="_msg964"> <source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">158</context></context-group> </trans-unit> - <trans-unit id="_msg967"> + <trans-unit id="_msg965"> <source xml:space="preserve">Error: Got key that was not hex: %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">159</context></context-group> </trans-unit> - <trans-unit id="_msg968"> + <trans-unit id="_msg966"> <source xml:space="preserve">Error: Got value that was not hex: %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">160</context></context-group> </trans-unit> - <trans-unit id="_msg969"> + <trans-unit id="_msg967"> <source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">161</context></context-group> </trans-unit> - <trans-unit id="_msg970"> + <trans-unit id="_msg968"> <source xml:space="preserve">Error: Missing checksum</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">162</context></context-group> </trans-unit> - <trans-unit id="_msg971"> + <trans-unit id="_msg969"> <source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">163</context></context-group> </trans-unit> - <trans-unit id="_msg972"> + <trans-unit id="_msg970"> <source xml:space="preserve">Error: Unable to write record to new wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg973"> + <trans-unit id="_msg971"> <source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">165</context></context-group> </trans-unit> - <trans-unit id="_msg974"> + <trans-unit id="_msg972"> <source xml:space="preserve">Failed to rescan the wallet during initialization</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">166</context></context-group> </trans-unit> - <trans-unit id="_msg975"> + <trans-unit id="_msg973"> <source xml:space="preserve">Failed to verify database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">167</context></context-group> </trans-unit> - <trans-unit id="_msg976"> + <trans-unit id="_msg974"> <source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">168</context></context-group> </trans-unit> - <trans-unit id="_msg977"> + <trans-unit id="_msg975"> <source xml:space="preserve">Ignoring duplicate -wallet %s.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">169</context></context-group> </trans-unit> - <trans-unit id="_msg978"> + <trans-unit id="_msg976"> <source xml:space="preserve">Importing…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg979"> + <trans-unit id="_msg977"> <source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">171</context></context-group> </trans-unit> - <trans-unit id="_msg980"> + <trans-unit id="_msg978"> <source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg981"> + <trans-unit id="_msg979"> <source xml:space="preserve">Insufficient funds</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg982"> + <trans-unit id="_msg980"> <source xml:space="preserve">Invalid -i2psam address or hostname: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg983"> + <trans-unit id="_msg981"> <source xml:space="preserve">Invalid -onion address or hostname: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">175</context></context-group> </trans-unit> - <trans-unit id="_msg984"> + <trans-unit id="_msg982"> <source xml:space="preserve">Invalid -proxy address or hostname: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg985"> + <trans-unit id="_msg983"> <source xml:space="preserve">Invalid P2P permission: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg986"> + <trans-unit id="_msg984"> <source xml:space="preserve">Invalid amount for -%s=<amount>: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg987"> + <trans-unit id="_msg985"> <source xml:space="preserve">Invalid amount for -discardfee=<amount>: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">179</context></context-group> </trans-unit> - <trans-unit id="_msg988"> + <trans-unit id="_msg986"> <source xml:space="preserve">Invalid amount for -fallbackfee=<amount>: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg989"> + <trans-unit id="_msg987"> <source xml:space="preserve">Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">181</context></context-group> </trans-unit> - <trans-unit id="_msg990"> + <trans-unit id="_msg988"> <source xml:space="preserve">Invalid netmask specified in -whitelist: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">182</context></context-group> </trans-unit> - <trans-unit id="_msg991"> + <trans-unit id="_msg989"> <source xml:space="preserve">Loading P2P addresses…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">183</context></context-group> </trans-unit> - <trans-unit id="_msg992"> + <trans-unit id="_msg990"> <source xml:space="preserve">Loading banlist…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">184</context></context-group> </trans-unit> - <trans-unit id="_msg993"> + <trans-unit id="_msg991"> <source xml:space="preserve">Loading block index…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">185</context></context-group> </trans-unit> - <trans-unit id="_msg994"> + <trans-unit id="_msg992"> <source xml:space="preserve">Loading wallet…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">186</context></context-group> </trans-unit> - <trans-unit id="_msg995"> + <trans-unit id="_msg993"> <source xml:space="preserve">Need to specify a port with -whitebind: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg996"> + <trans-unit id="_msg994"> <source xml:space="preserve">No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">188</context></context-group> </trans-unit> - <trans-unit id="_msg997"> + <trans-unit id="_msg995"> <source xml:space="preserve">Not enough file descriptors available.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">189</context></context-group> </trans-unit> - <trans-unit id="_msg998"> + <trans-unit id="_msg996"> <source xml:space="preserve">Prune cannot be configured with a negative value.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">190</context></context-group> </trans-unit> - <trans-unit id="_msg999"> + <trans-unit id="_msg997"> <source xml:space="preserve">Prune mode is incompatible with -coinstatsindex.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">191</context></context-group> </trans-unit> - <trans-unit id="_msg1000"> + <trans-unit id="_msg998"> <source xml:space="preserve">Prune mode is incompatible with -txindex.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">192</context></context-group> </trans-unit> - <trans-unit id="_msg1001"> + <trans-unit id="_msg999"> <source xml:space="preserve">Pruning blockstore…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">193</context></context-group> </trans-unit> - <trans-unit id="_msg1002"> + <trans-unit id="_msg1000"> <source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">194</context></context-group> </trans-unit> - <trans-unit id="_msg1003"> + <trans-unit id="_msg1001"> <source xml:space="preserve">Replaying blocks…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">195</context></context-group> </trans-unit> - <trans-unit id="_msg1004"> + <trans-unit id="_msg1002"> <source xml:space="preserve">Rescanning…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">196</context></context-group> </trans-unit> - <trans-unit id="_msg1005"> + <trans-unit id="_msg1003"> <source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">197</context></context-group> </trans-unit> - <trans-unit id="_msg1006"> + <trans-unit id="_msg1004"> <source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">198</context></context-group> </trans-unit> - <trans-unit id="_msg1007"> + <trans-unit id="_msg1005"> <source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">199</context></context-group> </trans-unit> - <trans-unit id="_msg1008"> + <trans-unit id="_msg1006"> <source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">200</context></context-group> </trans-unit> - <trans-unit id="_msg1009"> + <trans-unit id="_msg1007"> <source xml:space="preserve">Section [%s] is not recognized.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">201</context></context-group> </trans-unit> - <trans-unit id="_msg1010"> + <trans-unit id="_msg1008"> <source xml:space="preserve">Signing transaction failed</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">202</context></context-group> </trans-unit> - <trans-unit id="_msg1011"> + <trans-unit id="_msg1009"> <source xml:space="preserve">Specified -walletdir "%s" does not exist</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">203</context></context-group> </trans-unit> - <trans-unit id="_msg1012"> + <trans-unit id="_msg1010"> <source xml:space="preserve">Specified -walletdir "%s" is a relative path</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">204</context></context-group> </trans-unit> - <trans-unit id="_msg1013"> + <trans-unit id="_msg1011"> <source xml:space="preserve">Specified -walletdir "%s" is not a directory</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">205</context></context-group> </trans-unit> - <trans-unit id="_msg1014"> + <trans-unit id="_msg1012"> <source xml:space="preserve">Specified blocks directory "%s" does not exist.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg1015"> + <trans-unit id="_msg1013"> <source xml:space="preserve">Starting network threads…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">207</context></context-group> </trans-unit> - <trans-unit id="_msg1016"> + <trans-unit id="_msg1014"> <source xml:space="preserve">The source code is available from %s.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">208</context></context-group> </trans-unit> - <trans-unit id="_msg1017"> + <trans-unit id="_msg1015"> <source xml:space="preserve">The specified config file %s does not exist</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">209</context></context-group> </trans-unit> - <trans-unit id="_msg1018"> + <trans-unit id="_msg1016"> <source xml:space="preserve">The transaction amount is too small to pay the fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">210</context></context-group> </trans-unit> - <trans-unit id="_msg1019"> + <trans-unit id="_msg1017"> <source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">211</context></context-group> </trans-unit> - <trans-unit id="_msg1020"> + <trans-unit id="_msg1018"> <source xml:space="preserve">This is experimental software.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg1021"> + <trans-unit id="_msg1019"> <source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">213</context></context-group> </trans-unit> - <trans-unit id="_msg1022"> + <trans-unit id="_msg1020"> <source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">214</context></context-group> </trans-unit> - <trans-unit id="_msg1023"> + <trans-unit id="_msg1021"> <source xml:space="preserve">Transaction amount too small</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg1024"> + <trans-unit id="_msg1022"> <source xml:space="preserve">Transaction amounts must not be negative</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> - <trans-unit id="_msg1025"> + <trans-unit id="_msg1023"> <source xml:space="preserve">Transaction has too long of a mempool chain</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">217</context></context-group> </trans-unit> - <trans-unit id="_msg1026"> + <trans-unit id="_msg1024"> <source xml:space="preserve">Transaction must have at least one recipient</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> - <trans-unit id="_msg1027"> + <trans-unit id="_msg1025"> <source xml:space="preserve">Transaction too large</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">219</context></context-group> </trans-unit> - <trans-unit id="_msg1028"> + <trans-unit id="_msg1026"> <source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">220</context></context-group> </trans-unit> - <trans-unit id="_msg1029"> + <trans-unit id="_msg1027"> <source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">221</context></context-group> </trans-unit> - <trans-unit id="_msg1030"> + <trans-unit id="_msg1028"> <source xml:space="preserve">Unable to create the PID file '%s': %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg1031"> + <trans-unit id="_msg1029"> <source xml:space="preserve">Unable to generate initial keys</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">223</context></context-group> </trans-unit> - <trans-unit id="_msg1032"> + <trans-unit id="_msg1030"> <source xml:space="preserve">Unable to generate keys</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">224</context></context-group> </trans-unit> - <trans-unit id="_msg1033"> + <trans-unit id="_msg1031"> <source xml:space="preserve">Unable to open %s for writing</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg1034"> + <trans-unit id="_msg1032"> <source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg1035"> + <trans-unit id="_msg1033"> <source xml:space="preserve">Unknown -blockfilterindex value %s.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">227</context></context-group> </trans-unit> - <trans-unit id="_msg1036"> + <trans-unit id="_msg1034"> <source xml:space="preserve">Unknown address type '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> - <trans-unit id="_msg1037"> + <trans-unit id="_msg1035"> <source xml:space="preserve">Unknown change type '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">229</context></context-group> </trans-unit> - <trans-unit id="_msg1038"> + <trans-unit id="_msg1036"> <source xml:space="preserve">Unknown network specified in -onlynet: '%s'</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">230</context></context-group> </trans-unit> - <trans-unit id="_msg1039"> + <trans-unit id="_msg1037"> <source xml:space="preserve">Unsupported logging category %s=%s.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> - <trans-unit id="_msg1040"> + <trans-unit id="_msg1038"> <source xml:space="preserve">Upgrading UTXO database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">232</context></context-group> </trans-unit> - <trans-unit id="_msg1041"> + <trans-unit id="_msg1039"> <source xml:space="preserve">Upgrading txindex database</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">233</context></context-group> </trans-unit> - <trans-unit id="_msg1042"> + <trans-unit id="_msg1040"> <source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">234</context></context-group> </trans-unit> - <trans-unit id="_msg1043"> + <trans-unit id="_msg1041"> <source xml:space="preserve">Verifying blocks…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">235</context></context-group> </trans-unit> - <trans-unit id="_msg1044"> + <trans-unit id="_msg1042"> <source xml:space="preserve">Verifying wallet(s)…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">236</context></context-group> </trans-unit> - <trans-unit id="_msg1045"> + <trans-unit id="_msg1043"> <source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">237</context></context-group> </trans-unit> - <trans-unit id="_msg1046"> + <trans-unit id="_msg1044"> <source xml:space="preserve">Warning: unknown new rules activated (versionbit %i)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">238</context></context-group> diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 11441481bb..fff079d5db 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -132,6 +132,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const } else if (role == Qt::TextAlignmentRole) { switch (column) { case NetNodeId: + return QVariant(Qt::AlignRight | Qt::AlignVCenter); case Address: return {}; case ConnectionType: diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 1ecc2f67ef..ec3d970a7f 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -10,7 +10,10 @@ #include <qt/walletmodel.h> #include <clientversion.h> +#include <interfaces/wallet.h> +#include <key_io.h> #include <streams.h> +#include <util/string.h> #include <utility> @@ -21,10 +24,9 @@ RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) { // Load entries from wallet - std::vector<std::string> vReceiveRequests; - parent->loadReceiveRequests(vReceiveRequests); - for (const std::string& request : vReceiveRequests) + for (const std::string& request : parent->wallet().getAddressReceiveRequests()) { addNewRequest(request); + } /* These columns must match the indices in the ColumnIndex enumeration */ columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle(); @@ -150,7 +152,7 @@ bool RecentRequestsTableModel::removeRows(int row, int count, const QModelIndex for (int i = 0; i < count; ++i) { const RecentRequestEntry* rec = &list[row+i]; - if (!walletModel->saveReceiveRequest(rec->recipient.address.toStdString(), rec->id, "")) + if (!walletModel->wallet().setAddressReceiveRequest(DecodeDestination(rec->recipient.address.toStdString()), ToString(rec->id), "")) return false; } @@ -179,7 +181,7 @@ void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient CDataStream ss(SER_DISK, CLIENT_VERSION); ss << newEntry; - if (!walletModel->saveReceiveRequest(recipient.address.toStdString(), newEntry.id, ss.str())) + if (!walletModel->wallet().setAddressReceiveRequest(DecodeDestination(recipient.address.toStdString()), ToString(newEntry.id), ss.str())) return; addNewRequest(newEntry); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 83a111e9c8..e6e767c5af 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -34,9 +34,12 @@ #include <wallet/wallet.h> #endif +#include <QAbstractButton> #include <QDateTime> #include <QFont> #include <QKeyEvent> +#include <QLatin1String> +#include <QLocale> #include <QMenu> #include <QMessageBox> #include <QScreen> @@ -44,9 +47,10 @@ #include <QSettings> #include <QString> #include <QStringList> +#include <QStyledItemDelegate> #include <QTime> #include <QTimer> - +#include <QVariant> const int CONSOLE_HISTORY = 50; const int INITIAL_TRAFFIC_GRAPH_MINS = 30; @@ -128,6 +132,20 @@ public: } }; +class PeerIdViewDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit PeerIdViewDelegate(QObject* parent = nullptr) + : QStyledItemDelegate(parent) {} + + QString displayText(const QVariant& value, const QLocale& locale) const override + { + // Additional spaces should visually separate right-aligned content + // from the next column to the right. + return value.toString() + QLatin1String(" "); + } +}; #include <qt/rpcconsole.moc> @@ -469,6 +487,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty ui->splitter->restoreState(settings.value("RPCConsoleWidgetPeersTabSplitterSizes").toByteArray()); } + m_peer_widget_header_state = settings.value("PeersTabPeerHeaderState").toByteArray(); + m_banlist_widget_header_state = settings.value("PeersTabBanlistHeaderState").toByteArray(); + constexpr QChar nonbreaking_hyphen(8209); const std::vector<QString> CONNECTION_TYPE_DOC{ tr("Inbound: initiated by peer"), @@ -513,9 +534,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty ui->lineEdit->setMaxLength(16 * 1024 * 1024); ui->messagesWidget->installEventFilter(this); - connect(ui->clearButton, &QPushButton::clicked, [this] { clear(); }); - connect(ui->fontBiggerButton, &QPushButton::clicked, this, &RPCConsole::fontBigger); - connect(ui->fontSmallerButton, &QPushButton::clicked, this, &RPCConsole::fontSmaller); + connect(ui->clearButton, &QAbstractButton::clicked, [this] { clear(); }); + connect(ui->fontBiggerButton, &QAbstractButton::clicked, this, &RPCConsole::fontBigger); + connect(ui->fontSmallerButton, &QAbstractButton::clicked, this, &RPCConsole::fontSmaller); connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear); // disable the wallet selector by default @@ -552,6 +573,9 @@ RPCConsole::~RPCConsole() settings.setValue("RPCConsoleWidgetPeersTabSplitterSizes", ui->splitter->saveState()); } + settings.setValue("PeersTabPeerHeaderState", m_peer_widget_header_state); + settings.setValue("PeersTabBanlistHeaderState", m_banlist_widget_header_state); + m_node.rpcUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete ui; @@ -640,10 +664,14 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu); - ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH); - ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); - ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); + + if (!ui->peerWidget->horizontalHeader()->restoreState(m_peer_widget_header_state)) { + ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH); + ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); + ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); + } ui->peerWidget->horizontalHeader()->setStretchLastSection(true); + ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); // create peer table context menu peersTableContextMenu = new QMenu(this); @@ -664,8 +692,11 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu); - ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH); - ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); + + if (!ui->banlistWidget->horizontalHeader()->restoreState(m_banlist_widget_header_state)) { + ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH); + ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); + } ui->banlistWidget->horizontalHeader()->setStretchLastSection(true); // create ban table context menu @@ -816,23 +847,29 @@ void RPCConsole::clear(bool keep_prompt) ).arg(fixedFontInfo.family(), QString("%1pt").arg(consoleFontSize)) ); - message(CMD_REPLY, - tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + - "<br>" + - tr("Use up and down arrows to navigate history, and %1 to clear screen.") - .arg("<b>" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "</b>") + - "<br>" + - tr("Use %1 and %2 to increase or decrease the font size.") - .arg("<b>" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "</b>") - .arg("<b>" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "</b>") + - "<br>" + - tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + - "<br>" + - tr("For more information on using this console type %1.").arg("<b>help-console</b>") + - "<br><span class=\"secwarning\"><br>" + - tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") + - "</span>", - true); + static const QString welcome_message = + /*: RPC console welcome message. + Placeholders %7 and %8 are style tags for the warning content, and + they are not space separated from the rest of the text intentionally. */ + tr("Welcome to the %1 RPC console.\n" + "Use up and down arrows to navigate history, and %2 to clear screen.\n" + "Use %3 and %4 to increase or decrease the font size.\n" + "Type %5 for an overview of available commands.\n" + "For more information on using this console, type %6.\n" + "\n" + "%7WARNING: Scammers have been active, telling users to type" + " commands here, stealing their wallet contents. Do not use this console" + " without fully understanding the ramifications of a command.%8") + .arg(PACKAGE_NAME, + "<b>" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "</b>", + "<b>" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "</b>", + "<b>" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "</b>", + "<b>help</b>", + "<b>help-console</b>", + "<span class=\"secwarning\">", + "<span>"); + + message(CMD_REPLY, welcome_message, true); } void RPCConsole::keyPressEvent(QKeyEvent *event) @@ -924,57 +961,71 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) void RPCConsole::on_lineEdit_returnPressed() { - QString cmd = ui->lineEdit->text(); + QString cmd = ui->lineEdit->text().trimmed(); - if(!cmd.isEmpty()) - { - std::string strFilteredCmd; - try { - std::string dummy; - if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false, &strFilteredCmd)) { - // Failed to parse command, so we cannot even filter it for the history - throw std::runtime_error("Invalid command line"); - } - } catch (const std::exception& e) { - QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what())); - return; + if (cmd.isEmpty()) { + return; + } + + std::string strFilteredCmd; + try { + std::string dummy; + if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false, &strFilteredCmd)) { + // Failed to parse command, so we cannot even filter it for the history + throw std::runtime_error("Invalid command line"); } + } catch (const std::exception& e) { + QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what())); + return; + } - ui->lineEdit->clear(); + // A special case allows to request shutdown even a long-running command is executed. + if (cmd == QLatin1String("stop")) { + std::string dummy; + RPCExecuteCommandLine(m_node, dummy, cmd.toStdString()); + return; + } + + if (m_is_executing) { + return; + } - cmdBeforeBrowsing = QString(); + ui->lineEdit->clear(); #ifdef ENABLE_WALLET - WalletModel* wallet_model = ui->WalletSelector->currentData().value<WalletModel*>(); + WalletModel* wallet_model = ui->WalletSelector->currentData().value<WalletModel*>(); - if (m_last_wallet_model != wallet_model) { - if (wallet_model) { - message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(wallet_model->getWalletName())); - } else { - message(CMD_REQUEST, tr("Executing command without any wallet")); - } - m_last_wallet_model = wallet_model; + if (m_last_wallet_model != wallet_model) { + if (wallet_model) { + message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(wallet_model->getWalletName())); + } else { + message(CMD_REQUEST, tr("Executing command without any wallet")); } -#endif - - message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); - Q_EMIT cmdRequest(cmd, m_last_wallet_model); - - cmd = QString::fromStdString(strFilteredCmd); - - // Remove command, if already in history - history.removeOne(cmd); - // Append command to history - history.append(cmd); - // Enforce maximum history size - while(history.size() > CONSOLE_HISTORY) - history.removeFirst(); - // Set pointer to end of history - historyPtr = history.size(); + m_last_wallet_model = wallet_model; + } +#endif // ENABLE_WALLET - // Scroll console view to end - scrollToEnd(); + message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); + //: A console message indicating an entered command is currently being executed. + message(CMD_REPLY, tr("Executing…")); + m_is_executing = true; + Q_EMIT cmdRequest(cmd, m_last_wallet_model); + + cmd = QString::fromStdString(strFilteredCmd); + + // Remove command, if already in history + history.removeOne(cmd); + // Append command to history + history.append(cmd); + // Enforce maximum history size + while (history.size() > CONSOLE_HISTORY) { + history.removeFirst(); } + // Set pointer to end of history + historyPtr = history.size(); + + // Scroll console view to end + scrollToEnd(); } void RPCConsole::browseHistory(int offset) @@ -1004,7 +1055,13 @@ void RPCConsole::startExecutor() executor->moveToThread(&thread); // Replies from executor object must go to this object - connect(executor, &RPCExecutor::reply, this, qOverload<int, const QString&>(&RPCConsole::message)); + connect(executor, &RPCExecutor::reply, this, [this](int category, const QString& command) { + // Remove "Executing…" message. + ui->messagesWidget->undo(); + message(category, command); + scrollToEnd(); + m_is_executing = false; + }); // Requests from this object must go to executor connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); @@ -1079,7 +1136,7 @@ void RPCConsole::updateDetailWidget() if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings.isEmpty() ? ts.from : QLatin1Char('/') + ts.from); if (bip152_hb_settings.isEmpty()) bip152_hb_settings = ts.no; ui->peerHighBandwidth->setText(bip152_hb_settings); - const int64_t time_now{GetSystemTimeInSeconds()}; + const int64_t time_now{GetTimeSeconds()}; ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.nTimeConnected)); ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.nLastBlockTime)); ui->peerLastTx->setText(TimeDurationField(time_now, stats->nodeStats.nLastTXTime)); @@ -1145,6 +1202,11 @@ void RPCConsole::showEvent(QShowEvent *event) void RPCConsole::hideEvent(QHideEvent *event) { + // It is too late to call QHeaderView::saveState() in ~RPCConsole(), as all of + // the columns of QTableView child widgets will have zero width at that moment. + m_peer_widget_header_state = ui->peerWidget->horizontalHeader()->saveState(); + m_banlist_widget_header_state = ui->banlistWidget->horizontalHeader()->saveState(); + QWidget::hideEvent(event); if (!clientModel || !clientModel->getPeerTableModel()) diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 55a1decceb..2412ae543c 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -10,9 +10,10 @@ #include <net.h> -#include <QWidget> +#include <QByteArray> #include <QCompleter> #include <QThread> +#include <QWidget> class ClientModel; class PlatformStyle; @@ -166,6 +167,9 @@ private: QCompleter *autoCompleter = nullptr; QThread thread; WalletModel* m_last_wallet_model{nullptr}; + bool m_is_executing{false}; + QByteArray m_peer_widget_header_state; + QByteArray m_banlist_widget_header_state; /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index c1d5f84be5..cb3dbd2267 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -40,7 +40,7 @@ void TestRpcCommand(RPCConsole* console) QTest::keyClicks(lineEdit, "getblockchaininfo"); QTest::keyClick(lineEdit, Qt::Key_Return); QVERIFY(mw_spy.wait(1000)); - QCOMPARE(mw_spy.count(), 2); + QCOMPARE(mw_spy.count(), 4); QString output = messagesWidget->toPlainText(); UniValue value; value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString()); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 26f568b16a..ea35f80cf5 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -224,6 +224,7 @@ void TestGUI(interfaces::Node& node) int initialRowCount = requestTableModel->rowCount({}); QPushButton* requestPaymentButton = receiveCoinsDialog.findChild<QPushButton*>("receiveButton"); requestPaymentButton->click(); + QString address; for (QWidget* widget : QApplication::topLevelWidgets()) { if (widget->inherits("ReceiveRequestDialog")) { ReceiveRequestDialog* receiveRequestDialog = qobject_cast<ReceiveRequestDialog*>(widget); @@ -232,6 +233,9 @@ void TestGUI(interfaces::Node& node) QString uri = receiveRequestDialog->QObject::findChild<QLabel*>("uri_content")->text(); QCOMPARE(uri.count("bitcoin:"), 2); QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("address_tag")->text(), QString("Address:")); + QVERIFY(address.isEmpty()); + address = receiveRequestDialog->QObject::findChild<QLabel*>("address_content")->text(); + QVERIFY(!address.isEmpty()); QCOMPARE(uri.count("amount=0.00000001"), 2); QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_tag")->text(), QString("Amount:")); @@ -258,12 +262,30 @@ void TestGUI(interfaces::Node& node) int currentRowCount = requestTableModel->rowCount({}); QCOMPARE(currentRowCount, initialRowCount+1); + // Check addition to wallet + std::vector<std::string> requests = walletModel.wallet().getAddressReceiveRequests(); + QCOMPARE(requests.size(), size_t{1}); + RecentRequestEntry entry; + CDataStream{MakeUCharSpan(requests[0]), SER_DISK, CLIENT_VERSION} >> entry; + QCOMPARE(entry.nVersion, int{1}); + QCOMPARE(entry.id, int64_t{1}); + QVERIFY(entry.date.isValid()); + QCOMPARE(entry.recipient.address, address); + QCOMPARE(entry.recipient.label, QString{"TEST_LABEL_1"}); + QCOMPARE(entry.recipient.amount, CAmount{1}); + QCOMPARE(entry.recipient.message, QString{"TEST_MESSAGE_1"}); + QCOMPARE(entry.recipient.sPaymentRequest, std::string{}); + QCOMPARE(entry.recipient.authenticatedMerchant, QString{}); + // Check Remove button QTableView* table = receiveCoinsDialog.findChild<QTableView*>("recentRequestsView"); table->selectRow(currentRowCount-1); QPushButton* removeRequestButton = receiveCoinsDialog.findChild<QPushButton*>("removeRequestButton"); removeRequestButton->click(); QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1); + + // Check removal from wallet + QCOMPARE(walletModel.wallet().getAddressReceiveRequests().size(), size_t{0}); } } // namespace diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index c152689f0b..aa26a01541 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -207,6 +207,9 @@ void WalletControllerActivity::showProgressDialog(const QString& label_text) m_progress_dialog->setCancelButton(nullptr); m_progress_dialog->setWindowModality(Qt::ApplicationModal); GUIUtil::PolishProgressDialog(m_progress_dialog); + // The setValue call forces QProgressDialog to start the internal duration estimation. + // See details in https://bugreports.qt.io/browse/QTBUG-47042. + m_progress_dialog->setValue(0); } void WalletControllerActivity::destroyProgressDialog() diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index cc6db8d33e..7c58b8afd2 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -466,25 +466,6 @@ void WalletModel::UnlockContext::CopyFrom(UnlockContext&& rhs) rhs.relock = false; } -void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests) -{ - vReceiveRequests = m_wallet->getDestValues("rr"); // receive request -} - -bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest) -{ - CTxDestination dest = DecodeDestination(sAddress); - - std::stringstream ss; - ss << nId; - std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata - - if (sRequest.empty()) - return m_wallet->eraseDestData(dest, key); - else - return m_wallet->addDestData(dest, key, sRequest); -} - bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) { CCoinControl coin_control; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 4ca8643444..b2ce5d69fb 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -135,9 +135,6 @@ public: UnlockContext requestUnlock(); - void loadReceiveRequests(std::vector<std::string>& vReceiveRequests); - bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest); - bool bumpFee(uint256 hash, uint256& new_hash); static bool isWalletEnabled(); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 4bae4cab41..cc9e1502f0 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -331,7 +331,6 @@ void WalletView::showProgress(const QString &title, int nProgress) progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100); GUIUtil::PolishProgressDialog(progressDialog); progressDialog->setWindowModality(Qt::ApplicationModal); - progressDialog->setMinimumDuration(0); progressDialog->setAutoClose(false); progressDialog->setValue(0); } else if (nProgress == 100) { diff --git a/src/rest.cpp b/src/rest.cpp index d41f374c49..747c7aea19 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -107,6 +107,27 @@ static CTxMemPool* GetMemPool(const std::any& context, HTTPRequest* req) return node_context->mempool.get(); } +/** + * Get the node context chainstatemanager. + * + * @param[in] req The HTTP request, whose status code will be set if node + * context chainstatemanager is not found. + * @returns Pointer to the chainstatemanager or nullptr if none found. + */ +static ChainstateManager* GetChainman(const std::any& context, HTTPRequest* req) +{ + auto node_context = util::AnyPtr<NodeContext>(context); + if (!node_context || !node_context->chainman) { + RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, + strprintf("%s:%d (%s)\n" + "Internal bug detected: Chainman disabled or instance not found!\n" + "You may report this issue here: %s\n", + __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT)); + return nullptr; + } + return node_context->chainman; +} + static RetFormat ParseDataFormat(std::string& param, const std::string& strReq) { const std::string::size_type pos = strReq.rfind('.'); @@ -181,7 +202,9 @@ static bool rest_headers(const std::any& context, std::vector<const CBlockIndex *> headers; headers.reserve(count); { - ChainstateManager& chainman = EnsureAnyChainman(context); + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); CChain& active_chain = chainman.ActiveChain(); tip = active_chain.Tip(); @@ -252,7 +275,9 @@ static bool rest_block(const std::any& context, CBlockIndex* pblockindex = nullptr; CBlockIndex* tip = nullptr; { - ChainstateManager& chainman = EnsureAnyChainman(context); + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); tip = chainman.ActiveChain().Tip(); pblockindex = chainman.m_blockman.LookupBlockIndex(hash); @@ -541,7 +566,9 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: std::string bitmapStringRepresentation; std::vector<bool> hits; bitmap.resize((vOutPoints.size() + 7) / 8); - ChainstateManager& chainman = EnsureAnyChainman(context); + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; { auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) { for (const COutPoint& vOutPoint : vOutPoints) { @@ -644,7 +671,9 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req, CBlockIndex* pblockindex = nullptr; { - ChainstateManager& chainman = EnsureAnyChainman(context); + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); const CChain& active_chain = chainman.ActiveChain(); if (blockheight > active_chain.Height()) { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 03f28239ba..83c1975d38 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1196,7 +1196,7 @@ static RPCHelpMan gettxoutsetinfo() CCoinsStats prev_stats{hash_type}; if (pindex->nHeight > 0) { - GetUTXOStats(coins_view, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), prev_stats, node.rpc_interruption_point, pindex->pprev); + GetUTXOStats(coins_view, *blockman, prev_stats, node.rpc_interruption_point, pindex->pprev); } UniValue block_info(UniValue::VOBJ); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 8190a2f006..6826e6fd07 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -378,8 +378,7 @@ static RPCHelpMan generateblock() // Add transactions block.vtx.insert(block.vtx.end(), txs.begin(), txs.end()); - CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)); - RegenerateCommitments(block, prev_block); + RegenerateCommitments(block, chainman); { LOCK(cs_main); diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 7cf25e0c82..2059628b54 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -301,6 +301,16 @@ public: return obj; } + UniValue operator()(const WitnessV1Taproot& tap) const + { + UniValue obj(UniValue::VOBJ); + obj.pushKV("isscript", true); + obj.pushKV("iswitness", true); + obj.pushKV("witness_version", 1); + obj.pushKV("witness_program", HexStr(tap)); + return obj; + } + UniValue operator()(const WitnessUnknown& id) const { UniValue obj(UniValue::VOBJ); diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index b54ba204f0..51cf8a7d62 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -241,9 +241,10 @@ public: class ConstPubkeyProvider final : public PubkeyProvider { CPubKey m_pubkey; + bool m_xonly; public: - ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey) : PubkeyProvider(exp_index), m_pubkey(pubkey) {} + ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly = false) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {} bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) override { key = m_pubkey; @@ -254,7 +255,7 @@ public: } bool IsRange() const override { return false; } size_t GetSize() const override { return m_pubkey.size(); } - std::string ToString() const override { return HexStr(m_pubkey); } + std::string ToString() const override { return m_xonly ? HexStr(m_pubkey).substr(2) : HexStr(m_pubkey); } bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override { CKey key; @@ -505,6 +506,7 @@ protected: public: DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {} DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(Vector(std::move(script))) {} + DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::vector<std::unique_ptr<DescriptorImpl>> scripts, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(std::move(scripts)) {} bool IsSolvable() const override { @@ -638,6 +640,20 @@ public: std::optional<OutputType> GetOutputType() const override { return std::nullopt; } }; +static std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) { + if (std::holds_alternative<PKHash>(dest) || + std::holds_alternative<ScriptHash>(dest)) { + return OutputType::LEGACY; + } + if (std::holds_alternative<WitnessV0KeyHash>(dest) || + std::holds_alternative<WitnessV0ScriptHash>(dest) || + std::holds_alternative<WitnessV1Taproot>(dest) || + std::holds_alternative<WitnessUnknown>(dest)) { + return OutputType::BECH32; + } + return std::nullopt; +} + /** A parsed addr(A) descriptor. */ class AddressDescriptor final : public DescriptorImpl { @@ -651,15 +667,7 @@ public: std::optional<OutputType> GetOutputType() const override { - switch (m_destination.index()) { - case 1 /* PKHash */: - case 2 /* ScriptHash */: return OutputType::LEGACY; - case 3 /* WitnessV0ScriptHash */: - case 4 /* WitnessV0KeyHash */: - case 5 /* WitnessUnknown */: return OutputType::BECH32; - case 0 /* CNoDestination */: - default: return std::nullopt; - } + return OutputTypeFromDestination(m_destination); } bool IsSingleType() const final { return true; } }; @@ -679,15 +687,7 @@ public: { CTxDestination dest; ExtractDestination(m_script, dest); - switch (dest.index()) { - case 1 /* PKHash */: - case 2 /* ScriptHash */: return OutputType::LEGACY; - case 3 /* WitnessV0ScriptHash */: - case 4 /* WitnessV0KeyHash */: - case 5 /* WitnessUnknown */: return OutputType::BECH32; - case 0 /* CNoDestination */: - default: return std::nullopt; - } + return OutputTypeFromDestination(dest); } bool IsSingleType() const final { return true; } }; @@ -695,10 +695,20 @@ public: /** A parsed pk(P) descriptor. */ class PKDescriptor final : public DescriptorImpl { +private: + const bool m_xonly; protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override + { + if (m_xonly) { + CScript script = CScript() << ToByteVector(XOnlyPubKey(keys[0])) << OP_CHECKSIG; + return Vector(std::move(script)); + } else { + return Vector(GetScriptForRawPubKey(keys[0])); + } + } public: - PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pk") {} + PKDescriptor(std::unique_ptr<PubkeyProvider> prov, bool xonly = false) : DescriptorImpl(Vector(std::move(prov)), "pk"), m_xonly(xonly) {} bool IsSingleType() const final { return true; } }; @@ -816,6 +826,56 @@ public: bool IsSingleType() const final { return true; } }; +/** A parsed tr(...) descriptor. */ +class TRDescriptor final : public DescriptorImpl +{ + std::vector<int> m_depths; +protected: + std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript> scripts, FlatSigningProvider& out) const override + { + TaprootBuilder builder; + assert(m_depths.size() == scripts.size()); + for (size_t pos = 0; pos < m_depths.size(); ++pos) { + builder.Add(m_depths[pos], scripts[pos], TAPROOT_LEAF_TAPSCRIPT); + } + if (!builder.IsComplete()) return {}; + assert(keys.size() == 1); + XOnlyPubKey xpk(keys[0]); + if (!xpk.IsFullyValid()) return {}; + builder.Finalize(xpk); + return Vector(GetScriptForDestination(builder.GetOutput())); + } + bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, bool priv, bool normalized) const override + { + if (m_depths.empty()) return true; + std::vector<bool> path; + for (size_t pos = 0; pos < m_depths.size(); ++pos) { + if (pos) ret += ','; + while ((int)path.size() <= m_depths[pos]) { + if (path.size()) ret += '{'; + path.push_back(false); + } + std::string tmp; + if (!m_subdescriptor_args[pos]->ToStringHelper(arg, tmp, priv, normalized)) return false; + ret += std::move(tmp); + while (!path.empty() && path.back()) { + if (path.size() > 1) ret += '}'; + path.pop_back(); + } + if (!path.empty()) path.back() = true; + } + return true; + } +public: + TRDescriptor(std::unique_ptr<PubkeyProvider> internal_key, std::vector<std::unique_ptr<DescriptorImpl>> descs, std::vector<int> depths) : + DescriptorImpl(Vector(std::move(internal_key)), std::move(descs), "tr"), m_depths(std::move(depths)) + { + assert(m_subdescriptor_args.size() == m_depths.size()); + } + std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; } + bool IsSingleType() const final { return true; } +}; + //////////////////////////////////////////////////////////////////////////// // Parser // //////////////////////////////////////////////////////////////////////////// @@ -825,6 +885,7 @@ enum class ParseScriptContext { P2SH, //!< Inside sh() (script becomes P2SH redeemScript) P2WPKH, //!< Inside wpkh() (no script, pubkey only) P2WSH, //!< Inside wsh() (script becomes v0 witness script) + P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf) }; /** Parse a key path, being passed a split list of elements (the first element is ignored). */ @@ -873,6 +934,13 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S error = "Uncompressed keys are not allowed"; return nullptr; } + } else if (data.size() == 32 && ctx == ParseScriptContext::P2TR) { + unsigned char fullkey[33] = {0x02}; + std::copy(data.begin(), data.end(), fullkey + 1); + pubkey.Set(std::begin(fullkey), std::end(fullkey)); + if (pubkey.IsFullyValid()) { + return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true); + } } error = strprintf("Pubkey '%s' is invalid", str); return nullptr; @@ -960,13 +1028,16 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); if (!pubkey) return nullptr; ++key_exp_index; - return std::make_unique<PKDescriptor>(std::move(pubkey)); + return std::make_unique<PKDescriptor>(std::move(pubkey), ctx == ParseScriptContext::P2TR); } - if (Func("pkh", expr)) { + if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && Func("pkh", expr)) { auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); if (!pubkey) return nullptr; ++key_exp_index; return std::make_unique<PKHDescriptor>(std::move(pubkey)); + } else if (Func("pkh", expr)) { + error = "Can only have pkh at top level, in sh(), or in wsh()"; + return nullptr; } if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error); @@ -977,7 +1048,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const error = "Can only have combo() at top level"; return nullptr; } - if ((sorted_multi = Func("sortedmulti", expr)) || Func("multi", expr)) { + if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && ((sorted_multi = Func("sortedmulti", expr)) || Func("multi", expr))) { auto threshold = Expr(expr); uint32_t thres; std::vector<std::unique_ptr<PubkeyProvider>> providers; @@ -1022,6 +1093,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const } } return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sorted_multi); + } else if (Func("sortedmulti", expr) || Func("multi", expr)) { + error = "Can only have multi/sortedmulti at top level, in sh(), or in wsh()"; + return nullptr; } if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) { auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error); @@ -1059,6 +1133,67 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const error = "Can only have addr() at top level"; return nullptr; } + if (ctx == ParseScriptContext::TOP && Func("tr", expr)) { + auto arg = Expr(expr); + auto internal_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); + if (!internal_key) return nullptr; + ++key_exp_index; + std::vector<std::unique_ptr<DescriptorImpl>> subscripts; //!< list of script subexpressions + std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts) + if (expr.size()) { + if (!Const(",", expr)) { + error = strprintf("tr: expected ',', got '%c'", expr[0]); + return nullptr; + } + /** The path from the top of the tree to what we're currently processing. + * branches[i] == false: left branch in the i'th step from the top; true: right branch. + */ + std::vector<bool> branches; + // Loop over all provided scripts. In every iteration exactly one script will be processed. + // Use a do-loop because inside this if-branch we expect at least one script. + do { + // First process all open braces. + while (Const("{", expr)) { + branches.push_back(false); // new left branch + if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT) { + error = strprintf("tr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT); + return nullptr; + } + } + // Process the actual script expression. + auto sarg = Expr(expr); + subscripts.emplace_back(ParseScript(key_exp_index, sarg, ParseScriptContext::P2TR, out, error)); + if (!subscripts.back()) return nullptr; + depths.push_back(branches.size()); + // Process closing braces; one is expected for every right branch we were in. + while (branches.size() && branches.back()) { + if (!Const("}", expr)) { + error = strprintf("tr(): expected '}' after script expression"); + return nullptr; + } + branches.pop_back(); // move up one level after encountering '}' + } + // If after that, we're at the end of a left branch, expect a comma. + if (branches.size() && !branches.back()) { + if (!Const(",", expr)) { + error = strprintf("tr(): expected ',' after script expression"); + return nullptr; + } + branches.back() = true; // And now we're in a right branch. + } + } while (branches.size()); + // After we've explored a whole tree, we must be at the end of the expression. + if (expr.size()) { + error = strprintf("tr(): expected ')' after script expression"); + return nullptr; + } + } + assert(TaprootBuilder::ValidDepths(depths)); + return std::make_unique<TRDescriptor>(std::move(internal_key), std::move(subscripts), std::move(depths)); + } else if (Func("tr", expr)) { + error = "Can only have tr at top level"; + return nullptr; + } if (ctx == ParseScriptContext::TOP && Func("raw", expr)) { std::string str(expr.begin(), expr.end()); if (!IsHex(str)) { diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index dc0f165be0..3c3c3ac1a8 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1484,9 +1484,8 @@ template PrecomputedTransactionData::PrecomputedTransactionData(const CTransacti template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo); static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash"); -static const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf"); -static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch"); -static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak"); +const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf"); +const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch"); static bool HandleMissingData(MissingDataBehavior mdb) { @@ -1869,10 +1868,8 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c } k = ss_branch.GetSHA256(); } - // Compute the tweak from the Merkle root and the internal pubkey. - k = (CHashWriter(HASHER_TAPTWEAK) << MakeSpan(p) << k).GetSHA256(); // Verify that the output pubkey matches the tweaked internal pubkey, after correcting for parity. - return q.CheckPayToContract(p, k, control[0] & 1); + return q.CheckTapTweak(p, k, control[0] & 1); } static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 212de17c7b..fa4ee83e04 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_SCRIPT_INTERPRETER_H #define BITCOIN_SCRIPT_INTERPRETER_H +#include <hash.h> #include <script/script_error.h> #include <span.h> #include <primitives/transaction.h> @@ -218,6 +219,9 @@ static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32; static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128; static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; +extern const CHashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it. +extern const CHashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it. + template <class T> uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 364fac3c84..a4b11cc0a9 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -6,8 +6,11 @@ #include <script/standard.h> #include <crypto/sha256.h> +#include <hash.h> #include <pubkey.h> +#include <script/interpreter.h> #include <script/script.h> +#include <util/strencodings.h> #include <string> @@ -155,15 +158,14 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned c std::vector<unsigned char> witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) { - vSolutionsRet.push_back(witnessprogram); + vSolutionsRet.push_back(std::move(witnessprogram)); return TxoutType::WITNESS_V0_KEYHASH; } if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) { - vSolutionsRet.push_back(witnessprogram); + vSolutionsRet.push_back(std::move(witnessprogram)); return TxoutType::WITNESS_V0_SCRIPTHASH; } if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE) { - vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); return TxoutType::WITNESS_V1_TAPROOT; } @@ -242,8 +244,13 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) addressRet = hash; return true; } - case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: { + WitnessV1Taproot tap; + std::copy(vSolutions[0].begin(), vSolutions[0].end(), tap.begin()); + addressRet = tap; + return true; + } + case TxoutType::WITNESS_UNKNOWN: { WitnessUnknown unk; unk.version = vSolutions[0][0]; std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program); @@ -329,6 +336,11 @@ public: return CScript() << OP_0 << ToByteVector(id); } + CScript operator()(const WitnessV1Taproot& tap) const + { + return CScript() << OP_1 << ToByteVector(tap); + } + CScript operator()(const WitnessUnknown& id) const { return CScript() << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length); @@ -361,3 +373,99 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) bool IsValidDestination(const CTxDestination& dest) { return dest.index() != 0; } + +/*static*/ TaprootBuilder::NodeInfo TaprootBuilder::Combine(NodeInfo&& a, NodeInfo&& b) +{ + NodeInfo ret; + /* Lexicographically sort a and b's hash, and compute parent hash. */ + if (a.hash < b.hash) { + ret.hash = (CHashWriter(HASHER_TAPBRANCH) << a.hash << b.hash).GetSHA256(); + } else { + ret.hash = (CHashWriter(HASHER_TAPBRANCH) << b.hash << a.hash).GetSHA256(); + } + return ret; +} + +void TaprootBuilder::Insert(TaprootBuilder::NodeInfo&& node, int depth) +{ + assert(depth >= 0 && (size_t)depth <= TAPROOT_CONTROL_MAX_NODE_COUNT); + /* We cannot insert a leaf at a lower depth while a deeper branch is unfinished. Doing + * so would mean the Add() invocations do not correspond to a DFS traversal of a + * binary tree. */ + if ((size_t)depth + 1 < m_branch.size()) { + m_valid = false; + return; + } + /* As long as an entry in the branch exists at the specified depth, combine it and propagate up. + * The 'node' variable is overwritten here with the newly combined node. */ + while (m_valid && m_branch.size() > (size_t)depth && m_branch[depth].has_value()) { + node = Combine(std::move(node), std::move(*m_branch[depth])); + m_branch.pop_back(); + if (depth == 0) m_valid = false; /* Can't propagate further up than the root */ + --depth; + } + if (m_valid) { + /* Make sure the branch is big enough to place the new node. */ + if (m_branch.size() <= (size_t)depth) m_branch.resize((size_t)depth + 1); + assert(!m_branch[depth].has_value()); + m_branch[depth] = std::move(node); + } +} + +/*static*/ bool TaprootBuilder::ValidDepths(const std::vector<int>& depths) +{ + std::vector<bool> branch; + for (int depth : depths) { + // This inner loop corresponds to effectively the same logic on branch + // as what Insert() performs on the m_branch variable. Instead of + // storing a NodeInfo object, just remember whether or not there is one + // at that depth. + if (depth < 0 || (size_t)depth > TAPROOT_CONTROL_MAX_NODE_COUNT) return false; + if ((size_t)depth + 1 < branch.size()) return false; + while (branch.size() > (size_t)depth && branch[depth]) { + branch.pop_back(); + if (depth == 0) return false; + --depth; + } + if (branch.size() <= (size_t)depth) branch.resize((size_t)depth + 1); + assert(!branch[depth]); + branch[depth] = true; + } + // And this check corresponds to the IsComplete() check on m_branch. + return branch.size() == 0 || (branch.size() == 1 && branch[0]); +} + +TaprootBuilder& TaprootBuilder::Add(int depth, const CScript& script, int leaf_version) +{ + assert((leaf_version & ~TAPROOT_LEAF_MASK) == 0); + if (!IsValid()) return *this; + /* Construct NodeInfo object with leaf hash. */ + NodeInfo node; + node.hash = (CHashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256(); + /* Insert into the branch. */ + Insert(std::move(node), depth); + return *this; +} + +TaprootBuilder& TaprootBuilder::AddOmitted(int depth, const uint256& hash) +{ + if (!IsValid()) return *this; + /* Construct NodeInfo object with the hash directly, and insert it into the branch. */ + NodeInfo node; + node.hash = hash; + Insert(std::move(node), depth); + return *this; +} + +TaprootBuilder& TaprootBuilder::Finalize(const XOnlyPubKey& internal_key) +{ + /* Can only call this function when IsComplete() is true. */ + assert(IsComplete()); + m_internal_key = internal_key; + auto ret = m_internal_key.CreateTapTweak(m_branch.size() == 0 ? nullptr : &m_branch[0]->hash); + assert(ret.has_value()); + std::tie(m_output_key, std::ignore) = *ret; + return *this; +} + +WitnessV1Taproot TaprootBuilder::GetOutput() { return WitnessV1Taproot{m_output_key}; } diff --git a/src/script/standard.h b/src/script/standard.h index 12ab9979a8..d7ea5cef27 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_SCRIPT_STANDARD_H #define BITCOIN_SCRIPT_STANDARD_H +#include <pubkey.h> #include <script/interpreter.h> #include <uint256.h> #include <util/hash_type.h> @@ -113,6 +114,12 @@ struct WitnessV0KeyHash : public BaseHash<uint160> }; CKeyID ToKeyID(const WitnessV0KeyHash& key_hash); +struct WitnessV1Taproot : public XOnlyPubKey +{ + WitnessV1Taproot() : XOnlyPubKey() {} + explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {} +}; + //! CTxDestination subtype to encode any future Witness version struct WitnessUnknown { @@ -142,11 +149,11 @@ struct WitnessUnknown * * ScriptHash: TxoutType::SCRIPTHASH destination (P2SH) * * WitnessV0ScriptHash: TxoutType::WITNESS_V0_SCRIPTHASH destination (P2WSH) * * WitnessV0KeyHash: TxoutType::WITNESS_V0_KEYHASH destination (P2WPKH) - * * WitnessUnknown: TxoutType::WITNESS_UNKNOWN/WITNESS_V1_TAPROOT destination (P2W???) - * (taproot outputs do not require their own type as long as no wallet support exists) + * * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR) + * * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W???) * A CTxDestination is the internal data type encoded in a bitcoin address */ -using CTxDestination = std::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown>; +using CTxDestination = std::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown>; /** Check whether a CTxDestination is a CNoDestination. */ bool IsValidDestination(const CTxDestination& dest); @@ -202,4 +209,82 @@ CScript GetScriptForRawPubKey(const CPubKey& pubkey); /** Generate a multisig script. */ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys); +/** Utility class to construct Taproot outputs from internal key and script tree. */ +class TaprootBuilder +{ +private: + /** Information associated with a node in the Merkle tree. */ + struct NodeInfo + { + /** Merkle hash of this node. */ + uint256 hash; + }; + /** Whether the builder is in a valid state so far. */ + bool m_valid = true; + + /** The current state of the builder. + * + * For each level in the tree, one NodeInfo object may be present. m_branch[0] + * is information about the root; further values are for deeper subtrees being + * explored. + * + * For every right branch taken to reach the position we're currently + * working in, there will be a (non-nullopt) entry in m_branch corresponding + * to the left branch at that level. + * + * For example, imagine this tree: - N0 - + * / \ + * N1 N2 + * / \ / \ + * A B C N3 + * / \ + * D E + * + * Initially, m_branch is empty. After processing leaf A, it would become + * {nullopt, nullopt, A}. When processing leaf B, an entry at level 2 already + * exists, and it would thus be combined with it to produce a level 1 one, + * resulting in {nullopt, N1}. Adding C and D takes us to {nullopt, N1, C} + * and {nullopt, N1, C, D} respectively. When E is processed, it is combined + * with D, and then C, and then N1, to produce the root, resulting in {N0}. + * + * This structure allows processing with just O(log n) overhead if the leaves + * are computed on the fly. + * + * As an invariant, there can never be nullopt entries at the end. There can + * also not be more than 128 entries (as that would mean more than 128 levels + * in the tree). The depth of newly added entries will always be at least + * equal to the current size of m_branch (otherwise it does not correspond + * to a depth-first traversal of a tree). m_branch is only empty if no entries + * have ever be processed. m_branch having length 1 corresponds to being done. + */ + std::vector<std::optional<NodeInfo>> m_branch; + + XOnlyPubKey m_internal_key; //!< The internal key, set when finalizing. + XOnlyPubKey m_output_key; //!< The output key, computed when finalizing. */ + + /** Combine information about a parent Merkle tree node from its child nodes. */ + static NodeInfo Combine(NodeInfo&& a, NodeInfo&& b); + /** Insert information about a node at a certain depth, and propagate information up. */ + void Insert(NodeInfo&& node, int depth); + +public: + /** Add a new script at a certain depth in the tree. Add() operations must be called + * in depth-first traversal order of binary tree. */ + TaprootBuilder& Add(int depth, const CScript& script, int leaf_version); + /** Like Add(), but for a Merkle node with a given hash to the tree. */ + TaprootBuilder& AddOmitted(int depth, const uint256& hash); + /** Finalize the construction. Can only be called when IsComplete() is true. + internal_key.IsFullyValid() must be true. */ + TaprootBuilder& Finalize(const XOnlyPubKey& internal_key); + + /** Return true if so far all input was valid. */ + bool IsValid() const { return m_valid; } + /** Return whether there were either no leaves, or the leaves form a Huffman tree. */ + bool IsComplete() const { return m_valid && (m_branch.size() == 0 || (m_branch.size() == 1 && m_branch[0].has_value())); } + /** Compute scriptPubKey (after Finalize()). */ + WitnessV1Taproot GetOutput(); + /** Check if a list of depths is legal (will lead to IsComplete()). */ + static bool ValidDepths(const std::vector<int>& depths); +}; + #endif // BITCOIN_SCRIPT_STANDARD_H diff --git a/src/serialize.h b/src/serialize.h index 5ef846b9e9..edf10440c6 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -226,12 +226,8 @@ template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N] template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(CharCast(a), N); } template<typename Stream> inline void Unserialize(Stream& s, Span<unsigned char>& span) { s.read(CharCast(span.data()), span.size()); } -template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } -template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; } - - - - +template <typename Stream> inline void Serialize(Stream& s, bool a) { uint8_t f = a; ser_writedata8(s, f); } +template <typename Stream> inline void Unserialize(Stream& s, bool& a) { uint8_t f = ser_readdata8(s); a = f; } /** diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index b523173a45..3779e7b964 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -2,15 +2,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <support/lockedpool.h> #include <util/system.h> -#include <test/util/setup_common.h> - +#include <limits> #include <memory> +#include <stdexcept> +#include <utility> +#include <vector> #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(allocator_tests) BOOST_AUTO_TEST_CASE(arena_tests) { diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp index 65ba2bab15..77b7758a17 100644 --- a/src/test/amount_tests.cpp +++ b/src/test/amount_tests.cpp @@ -4,11 +4,12 @@ #include <amount.h> #include <policy/feerate.h> -#include <test/util/setup_common.h> + +#include <limits> #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(amount_tests) BOOST_AUTO_TEST_CASE(MoneyRangeTest) { diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index a135c93786..a00888aae6 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -3,19 +3,19 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <arith_uint256.h> -#include <test/util/setup_common.h> #include <uint256.h> #include <boost/test/unit_test.hpp> #include <cmath> +#include <cstdint> #include <iomanip> #include <limits> #include <sstream> -#include <stdint.h> #include <string> +#include <vector> -BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(arith_uint256_tests) /// Convert vector to arith_uint256, via uint256 blob static inline arith_uint256 arith_uint256V(const std::vector<unsigned char>& vch) diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 3b44564ddb..22853555e2 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <test/util/setup_common.h> #include <util/strencodings.h> #include <boost/test/unit_test.hpp> @@ -10,7 +9,7 @@ using namespace std::literals; -BOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(base32_tests) BOOST_AUTO_TEST_CASE(base32_testvectors) { diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index 714fccffaa..9d1dfd46f1 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <test/util/setup_common.h> #include <util/strencodings.h> #include <boost/test/unit_test.hpp> @@ -10,7 +9,7 @@ using namespace std::literals; -BOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(base64_tests) BOOST_AUTO_TEST_CASE(base64_testvectors) { diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp index 2651e46430..c0344b3cbb 100644 --- a/src/test/bech32_tests.cpp +++ b/src/test/bech32_tests.cpp @@ -3,12 +3,13 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bech32.h> -#include <test/util/setup_common.h> #include <test/util/str.h> #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(bech32_tests, BasicTestingSetup) +#include <string> + +BOOST_AUTO_TEST_SUITE(bech32_tests) BOOST_AUTO_TEST_CASE(bech32_testvectors_valid) { diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 32329eb510..fb16c92647 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2020 The Bitcoin Core developers +// Copyright (c) 2013-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -87,6 +87,18 @@ TestVector test3 = "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L", 0); +TestVector test4 = + TestVector("3ddd5602285899a946114506157c7997e5444528f3003f6134712147db19b678") + ("xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa", + "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv", + 0x80000000) + ("xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m", + "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G", + 0x80000001) + ("xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt", + "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1", + 0); + static void RunTest(const TestVector &test) { std::vector<unsigned char> seed = ParseHex(test.strHexMaster); CExtKey key; @@ -135,4 +147,8 @@ BOOST_AUTO_TEST_CASE(bip32_test3) { RunTest(test3); } +BOOST_AUTO_TEST_CASE(bip32_test4) { + RunTest(test4); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 1cb1c002f4..2f532ef598 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -131,7 +131,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) // BlockUntilSyncedToCurrentChain should return false before index is started. BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain()); - BOOST_REQUIRE(filter_index.Start()); + BOOST_REQUIRE(filter_index.Start(::ChainstateActive())); // Allow filter index to catch up with the block index. constexpr int64_t timeout_ms = 10 * 1000; diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp index 2dbca4e8b6..4e75e74d77 100644 --- a/src/test/bswap_tests.cpp +++ b/src/test/bswap_tests.cpp @@ -3,11 +3,10 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <compat/byteswap.h> -#include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(bswap_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(bswap_tests) BOOST_AUTO_TEST_CASE(bswap_tests) { diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index bf7a80ae5c..106fcd2a33 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -32,7 +32,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) // is started. BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain()); - BOOST_REQUIRE(coin_stats_index.Start()); + BOOST_REQUIRE(coin_stats_index.Start(::ChainstateActive())); // Allow the CoinStatsIndex to catch up with the block index that is syncing // in a background thread. diff --git a/src/test/compilerbug_tests.cpp b/src/test/compilerbug_tests.cpp index b68bc279e1..a9cec624ae 100644 --- a/src/test/compilerbug_tests.cpp +++ b/src/test/compilerbug_tests.cpp @@ -3,9 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <boost/test/unit_test.hpp> -#include <test/util/setup_common.h> -BOOST_FIXTURE_TEST_SUITE(compilerbug_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(compilerbug_tests) #if defined(__GNUC__) // This block will also be built under clang, which is fine (as it supports noinline) diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index e2e7644dfa..b6f5938892 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) for (const bool obfuscate : {false, true}) { fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); - char key = 'k'; + uint8_t key{'k'}; uint256 in = InsecureRand256(); uint256 res; @@ -88,21 +88,21 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data) BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString()); //Simulate last block file number - "l" - char key_last_blockfile_number = 'l'; + uint8_t key_last_blockfile_number{'l'}; uint32_t lastblockfilenumber = InsecureRand32(); BOOST_CHECK(dbw.Write(key_last_blockfile_number, lastblockfilenumber)); BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32)); BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32); //Simulate Is Reindexing - "R" - char key_IsReindexing = 'R'; + uint8_t key_IsReindexing{'R'}; bool isInReindexing = InsecureRandBool(); BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing)); BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool)); BOOST_CHECK_EQUAL(isInReindexing, res_bool); //Simulate last block hash up to which UXTO covers - 'B' - char key_lastblockhash_uxto = 'B'; + uint8_t key_lastblockhash_uxto{'B'}; uint256 lastblock_hash = InsecureRand256(); BOOST_CHECK(dbw.Write(key_lastblockhash_uxto, lastblock_hash)); BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res)); @@ -129,11 +129,11 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); - char key = 'i'; + uint8_t key{'i'}; uint256 in = InsecureRand256(); - char key2 = 'j'; + uint8_t key2{'j'}; uint256 in2 = InsecureRand256(); - char key3 = 'k'; + uint8_t key3{'k'}; uint256 in3 = InsecureRand256(); uint256 res; @@ -166,10 +166,10 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering - char key = 'j'; + uint8_t key{'j'}; uint256 in = InsecureRand256(); BOOST_CHECK(dbw.Write(key, in)); - char key2 = 'k'; + uint8_t key2{'k'}; uint256 in2 = InsecureRand256(); BOOST_CHECK(dbw.Write(key2, in2)); @@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) // Be sure to seek past the obfuscation key (if it exists) it->Seek(key); - char key_res; + uint8_t key_res; uint256 val_res; BOOST_REQUIRE(it->GetKey(key_res)); @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false); - char key = 'k'; + uint8_t key{'k'}; uint256 in = InsecureRand256(); uint256 res; @@ -248,7 +248,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false); - char key = 'k'; + uint8_t key{'k'}; uint256 in = InsecureRand256(); uint256 res; @@ -334,7 +334,7 @@ struct StringContentsSerializer { void Serialize(Stream& s) const { for (size_t i = 0; i < str.size(); i++) { - s << str[i]; + s << uint8_t(str[i]); } } @@ -342,7 +342,7 @@ struct StringContentsSerializer { void Unserialize(Stream& s) { str.clear(); - char c = 0; + uint8_t c{0}; while (true) { try { s >> c; diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index 4a04eed463..759a70a857 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -32,13 +32,17 @@ void initialize_banman() FUZZ_TARGET_INIT(banman, initialize_banman) { + // The complexity is O(N^2), where N is the input size, because each call + // might call DumpBanlist (or other methods that are at least linear + // complexity of the input size). + int limit_max_ops{300}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); const fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist.dat"; fs::remove(banlist_file); { BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)}; - while (fuzzed_data_provider.ConsumeBool()) { + while (--limit_max_ops >= 0 && fuzzed_data_provider.ConsumeBool()) { CallOneOf( fuzzed_data_provider, [&] { @@ -52,7 +56,6 @@ FUZZ_TARGET_INIT(banman, initialize_banman) [&] { ban_man.ClearBanned(); }, - [] {}, [&] { ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); }, @@ -72,7 +75,6 @@ FUZZ_TARGET_INIT(banman, initialize_banman) [&] { ban_man.DumpBanlist(); }, - [] {}, [&] { ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); }); diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 878b5a27da..b509ee0b26 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -236,8 +236,9 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) // It is not allowed to call CheckTxInputs if CheckTransaction failed return; } - (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out); - assert(MoneyRange(tx_fee_out)); + if (Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out)) { + assert(MoneyRange(tx_fee_out)); + } }, [&] { const CTransaction transaction{random_mutable_transaction}; diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 1290c78712..700e368319 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -143,7 +143,7 @@ FUZZ_TARGET_DESERIALIZE(script_deserialize, { CScript script; DeserializeFromFuzzingInput(buffer, script); }) -FUZZ_TARGET_DESERIALIZE(sub_net_deserialize, { +FUZZ_TARGET_DESERIALIZE(subnet_deserialize, { CSubNet sub_net_1; DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION); AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION); @@ -223,7 +223,7 @@ FUZZ_TARGET_DESERIALIZE(coins_deserialize, { Coin coin; DeserializeFromFuzzingInput(buffer, coin); }) -FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, { +FUZZ_TARGET_DESERIALIZE(net_address_deserialize, { CNetAddr na; DeserializeFromFuzzingInput(buffer, na); if (na.IsAddrV1Compatible()) { @@ -231,7 +231,7 @@ FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, { } AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT); }) -FUZZ_TARGET_DESERIALIZE(service_deserialize, { +FUZZ_TARGET_DESERIALIZE(net_service_deserialize, { CService s; DeserializeFromFuzzingInput(buffer, s); if (s.IsAddrV1Compatible()) { diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 41a626c0ea..677bf39fd9 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -10,7 +10,7 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(hash_tests) BOOST_AUTO_TEST_CASE(murmurhash3) { diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp index 98b27994a6..e540b59b35 100644 --- a/src/test/merkleblock_tests.cpp +++ b/src/test/merkleblock_tests.cpp @@ -8,8 +8,10 @@ #include <boost/test/unit_test.hpp> +#include <set> +#include <vector> -BOOST_FIXTURE_TEST_SUITE(merkleblock_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(merkleblock_tests) /** * Create a CMerkleBlock using a list of txids which will be found in the diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 7a122bd8b0..46f88c1282 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -318,15 +318,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_CHECK(!addr.IsBindAny()); BOOST_CHECK_EQUAL(addr.ToString(), link_local); - // TORv2 - BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion")); - BOOST_REQUIRE(addr.IsValid()); - BOOST_REQUIRE(addr.IsTor()); - - BOOST_CHECK(!addr.IsI2P()); - BOOST_CHECK(!addr.IsBindAny()); - BOOST_CHECK(addr.IsAddrV1Compatible()); - BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion"); + // TORv2, no longer supported + BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion")); // TORv3 const char* torv3_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"; @@ -470,10 +463,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1) BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b"); s.clear(); - BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion")); - s << addr; - BOOST_CHECK_EQUAL(HexStr(s), "fd87d87eeb43f1f2f3f4f5f6f7f8f9fa"); - s.clear(); + // TORv2, no longer supported + BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion")); BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")); s << addr; @@ -508,10 +499,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2) BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b"); s.clear(); - BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion")); - s << addr; - BOOST_CHECK_EQUAL(HexStr(s), "030af1f2f3f4f5f6f7f8f9fa"); - s.clear(); + // TORv2, no longer supported + BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion")); BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion")); s << addr; @@ -617,26 +606,14 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); - // Valid TORv2. + // TORv2, no longer supported. s << MakeSpan(ParseHex("03" // network type (TORv2) "0a" // address length "f1f2f3f4f5f6f7f8f9fa")); // address s >> addr; - BOOST_CHECK(addr.IsValid()); - BOOST_CHECK(addr.IsTor()); - BOOST_CHECK(addr.IsAddrV1Compatible()); - BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion"); + BOOST_CHECK(!addr.IsValid()); BOOST_REQUIRE(s.empty()); - // Invalid TORv2, with bogus length. - s << MakeSpan(ParseHex("03" // network type (TORv2) - "07" // address length - "00")); // address - BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, - HasReason("BIP155 TORv2 address with length 7 (should be 10)")); - BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. - s.clear(); - // Valid TORv3. s << MakeSpan(ParseHex("04" // network type (TORv3) "20" // address length diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 3c47cf83e2..687d2f6747 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -44,13 +44,12 @@ static CNetAddr CreateInternal(const std::string& host) BOOST_AUTO_TEST_CASE(netbase_networks) { - BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE); - BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE); - BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4); - BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6); - BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_ONION); - BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL); - + BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4); + BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6); + BOOST_CHECK(ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion").GetNetwork() == NET_ONION); + BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL); } BOOST_AUTO_TEST_CASE(netbase_properties) @@ -73,7 +72,7 @@ BOOST_AUTO_TEST_CASE(netbase_properties) BOOST_CHECK(ResolveIP("2001:20::").IsRFC7343()); BOOST_CHECK(ResolveIP("FE80::").IsRFC4862()); BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052()); - BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor()); + BOOST_CHECK(ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion").IsTor()); BOOST_CHECK(ResolveIP("127.0.0.1").IsLocal()); BOOST_CHECK(ResolveIP("::1").IsLocal()); BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable()); @@ -133,18 +132,6 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535")); } -BOOST_AUTO_TEST_CASE(onioncat_test) -{ - // values from https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat - CNetAddr addr1(ResolveIP("5wyqrzbvrdsumnok.onion")); - CNetAddr addr2(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca")); - BOOST_CHECK(addr1 == addr2); - BOOST_CHECK(addr1.IsTor()); - BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion"); - BOOST_CHECK(addr1.IsRoutable()); - -} - BOOST_AUTO_TEST_CASE(embedded_test) { CNetAddr addr1(ResolveIP("1.2.3.4")); @@ -338,7 +325,6 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup) BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052 BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964 BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380 - BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_ONION, 239})); // Tor BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6 @@ -481,10 +467,10 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters) BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret)); BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com"s, ret)); BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com\0"s, ret)); - BOOST_CHECK(LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret)); - BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0"s, ret)); - BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com"s, ret)); - BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com\0"s, ret)); + BOOST_CHECK(LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"s, ret)); + BOOST_CHECK(!LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion\0"s, ret)); + BOOST_CHECK(!LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion\0example.com"s, ret)); + BOOST_CHECK(!LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion\0example.com\0"s, ret)); } // Since CNetAddr (un)ser is tested separately in net_tests.cpp here we only diff --git a/src/test/policy_fee_tests.cpp b/src/test/policy_fee_tests.cpp index 6d8872b11e..4a15be6ca6 100644 --- a/src/test/policy_fee_tests.cpp +++ b/src/test/policy_fee_tests.cpp @@ -5,11 +5,11 @@ #include <amount.h> #include <policy/fees.h> -#include <test/util/setup_common.h> - #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(policy_fee_tests, BasicTestingSetup) +#include <set> + +BOOST_AUTO_TEST_SUITE(policy_fee_tests) BOOST_AUTO_TEST_CASE(FeeRounder) { diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index 7da364d316..21576bb868 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -7,7 +7,9 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(reverselock_tests, BasicTestingSetup) +#include <stdexcept> + +BOOST_AUTO_TEST_SUITE(reverselock_tests) BOOST_AUTO_TEST_CASE(reverselock_basics) { diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 44fbfa5970..a01d3fa03a 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -3,10 +3,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <key.h> +#include <key_io.h> #include <script/script.h> #include <script/signingprovider.h> #include <script/standard.h> #include <test/util/setup_common.h> +#include <util/strencodings.h> #include <boost/test/unit_test.hpp> @@ -111,9 +113,8 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) s.clear(); s << OP_1 << ToByteVector(uint256::ZERO); BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_V1_TAPROOT); - BOOST_CHECK_EQUAL(solutions.size(), 2U); - BOOST_CHECK(solutions[0] == std::vector<unsigned char>{1}); - BOOST_CHECK(solutions[1] == ToByteVector(uint256::ZERO)); + BOOST_CHECK_EQUAL(solutions.size(), 1U); + BOOST_CHECK(solutions[0] == ToByteVector(uint256::ZERO)); // TxoutType::WITNESS_UNKNOWN s.clear(); @@ -379,4 +380,70 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) BOOST_CHECK(result == expected); } +BOOST_AUTO_TEST_CASE(script_standard_taproot_builder) +{ + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,0,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,1,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({0,2,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,0,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,1,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({1,2,2}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,0,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1,1}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,1,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,0}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,1}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2}), false); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2,3,4,5,6,7,8,9,10,11,12,14,14,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,31,31,31,31,31,31,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,128}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({128,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({129,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), false); + + XOnlyPubKey key_inner{ParseHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")}; + XOnlyPubKey key_1{ParseHex("c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5")}; + XOnlyPubKey key_2{ParseHex("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")}; + CScript script_1 = CScript() << ToByteVector(key_1) << OP_CHECKSIG; + CScript script_2 = CScript() << ToByteVector(key_2) << OP_CHECKSIG; + uint256 hash_3 = uint256S("31fe7061656bea2a36aa60a2f7ef940578049273746935d296426dc0afd86b68"); + + TaprootBuilder builder; + BOOST_CHECK(builder.IsValid() && builder.IsComplete()); + builder.Add(2, script_2, 0xc0); + BOOST_CHECK(builder.IsValid() && !builder.IsComplete()); + builder.AddOmitted(2, hash_3); + BOOST_CHECK(builder.IsValid() && !builder.IsComplete()); + builder.Add(1, script_1, 0xc0); + BOOST_CHECK(builder.IsValid() && builder.IsComplete()); + builder.Finalize(key_inner); + BOOST_CHECK(builder.IsValid() && builder.IsComplete()); + BOOST_CHECK_EQUAL(EncodeDestination(builder.GetOutput()), "bc1pj6gaw944fy0xpmzzu45ugqde4rz7mqj5kj0tg8kmr5f0pjq8vnaqgynnge"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 58709178a4..4b55e3bc26 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -24,7 +24,7 @@ protected: CTransactionRef txval; public: CSerializeMethodsTestSingle() = default; - CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, const CTransactionRef& txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(txvalin) + CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const uint8_t* charstrvalin, const CTransactionRef& txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(txvalin) { memcpy(charstrval, charstrvalin, sizeof(charstrval)); } @@ -70,8 +70,8 @@ BOOST_AUTO_TEST_CASE(sizes) BOOST_CHECK_EQUAL(sizeof(uint32_t), GetSerializeSize(uint32_t(0), 0)); BOOST_CHECK_EQUAL(sizeof(int64_t), GetSerializeSize(int64_t(0), 0)); BOOST_CHECK_EQUAL(sizeof(uint64_t), GetSerializeSize(uint64_t(0), 0)); - // Bool is serialized as char - BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(bool(0), 0)); + // Bool is serialized as uint8_t + BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(bool(0), 0)); // Sanity-check GetSerializeSize and c++ type matching BOOST_CHECK_EQUAL(GetSerializeSize(char(0), 0), 1U); @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(class_methods) int intval(100); bool boolval(true); std::string stringval("testing"); - const char charstrval[16] = "testing charstr"; + const uint8_t charstrval[16]{"testing charstr"}; CMutableTransaction txval; CTransactionRef tx_ref{MakeTransactionRef(txval)}; CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, tx_ref); diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp index 3e4d1dac9e..f5a8fc3aa6 100644 --- a/src/test/sync_tests.cpp +++ b/src/test/sync_tests.cpp @@ -8,6 +8,7 @@ #include <boost/test/unit_test.hpp> #include <mutex> +#include <stdexcept> namespace { template <typename MutexType> @@ -76,7 +77,7 @@ void TestInconsistentLockOrderDetected(MutexType& mutex1, MutexType& mutex2) NO_ } } // namespace -BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(sync_tests) BOOST_AUTO_TEST_CASE(potential_deadlock_detected) { diff --git a/src/test/torcontrol_tests.cpp b/src/test/torcontrol_tests.cpp index 41aa17988c..659caaef61 100644 --- a/src/test/torcontrol_tests.cpp +++ b/src/test/torcontrol_tests.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // -#include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> @@ -15,7 +14,7 @@ std::pair<std::string, std::string> SplitTorReplyLine(const std::string& s); std::map<std::string, std::string> ParseTorReplyMapping(const std::string& s); -BOOST_FIXTURE_TEST_SUITE(torcontrol_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(torcontrol_tests) static void CheckSplitTorReplyLine(std::string input, std::string command, std::string args) { diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 082655d811..d47c54fd6e 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -7,6 +7,7 @@ #include <script/standard.h> #include <test/util/setup_common.h> #include <util/time.h> +#include <validation.h> #include <boost/test/unit_test.hpp> @@ -27,7 +28,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) // BlockUntilSyncedToCurrentChain should return false before txindex is started. BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain()); - BOOST_REQUIRE(txindex.Start()); + BOOST_REQUIRE(txindex.Start(::ChainstateActive())); // Allow tx index to catch up with the block index. constexpr int64_t timeout_ms = 10 * 1000; diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index ae626d4613..b4744cabc7 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -13,8 +13,9 @@ #include <iomanip> #include <sstream> #include <string> +#include <vector> -BOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(uint256_tests) const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 0ac178443a..863c3ab565 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -246,8 +246,7 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa for (const CMutableTransaction& tx : txns) { block.vtx.push_back(MakeTransactionRef(tx)); } - CBlockIndex* prev_block = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)); - RegenerateCommitments(block, prev_block); + RegenerateCommitments(block, *Assert(m_node.chainman)); while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index aa95bc37e5..d463bcdd8e 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime) BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0); BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777); - auto time = GetSystemTimeInSeconds(); + auto time = GetTimeSeconds(); BOOST_CHECK_EQUAL(ParseISO8601DateTime(FormatISO8601DateTime(time)), time); } diff --git a/src/test/util_threadnames_tests.cpp b/src/test/util_threadnames_tests.cpp index f3f9fb2bff..a5b456dd7a 100644 --- a/src/test/util_threadnames_tests.cpp +++ b/src/test/util_threadnames_tests.cpp @@ -2,12 +2,12 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <test/util/setup_common.h> #include <util/string.h> #include <util/threadnames.h> #include <mutex> #include <set> +#include <string> #include <thread> #include <vector> @@ -17,7 +17,7 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(util_threadnames_tests, BasicTestingSetup) +BOOST_AUTO_TEST_SUITE(util_threadnames_tests) const std::string TEST_THREAD_NAME_BASE = "test_thread."; diff --git a/src/txdb.cpp b/src/txdb.cpp index c11d46cf88..762f71feb1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -16,22 +16,22 @@ #include <stdint.h> -static const char DB_COIN = 'C'; -static const char DB_COINS = 'c'; -static const char DB_BLOCK_FILES = 'f'; -static const char DB_BLOCK_INDEX = 'b'; +static constexpr uint8_t DB_COIN{'C'}; +static constexpr uint8_t DB_COINS{'c'}; +static constexpr uint8_t DB_BLOCK_FILES{'f'}; +static constexpr uint8_t DB_BLOCK_INDEX{'b'}; -static const char DB_BEST_BLOCK = 'B'; -static const char DB_HEAD_BLOCKS = 'H'; -static const char DB_FLAG = 'F'; -static const char DB_REINDEX_FLAG = 'R'; -static const char DB_LAST_BLOCK = 'l'; +static constexpr uint8_t DB_BEST_BLOCK{'B'}; +static constexpr uint8_t DB_HEAD_BLOCKS{'H'}; +static constexpr uint8_t DB_FLAG{'F'}; +static constexpr uint8_t DB_REINDEX_FLAG{'R'}; +static constexpr uint8_t DB_LAST_BLOCK{'l'}; namespace { struct CoinEntry { COutPoint* outpoint; - char key; + uint8_t key; explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {} SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); } @@ -143,7 +143,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { size_t CCoinsViewDB::EstimateSize() const { - return m_db->EstimateSize(DB_COIN, (char)(DB_COIN+1)); + return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1)); } CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(gArgs.GetDataDirNet() / "blocks" / "index", nCacheSize, fMemory, fWipe) { @@ -155,7 +155,7 @@ bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { bool CBlockTreeDB::WriteReindexing(bool fReindexing) { if (fReindexing) - return Write(DB_REINDEX_FLAG, '1'); + return Write(DB_REINDEX_FLAG, uint8_t{'1'}); else return Erase(DB_REINDEX_FLAG); } @@ -235,14 +235,14 @@ bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockF } bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { - return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); + return Write(std::make_pair(DB_FLAG, name), fValue ? uint8_t{'1'} : uint8_t{'0'}); } bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { - char ch; + uint8_t ch; if (!Read(std::make_pair(DB_FLAG, name), ch)) return false; - fValue = ch == '1'; + fValue = ch == uint8_t{'1'}; return true; } @@ -255,7 +255,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, // Load m_block_index while (pcursor->Valid()) { if (ShutdownRequested()) return false; - std::pair<char, uint256> key; + std::pair<uint8_t, uint256> key; if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) { CDiskBlockIndex diskindex; if (pcursor->GetValue(diskindex)) { diff --git a/src/uint256.h b/src/uint256.h index fadf2320af..d4917d0eac 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -75,7 +75,7 @@ public: return &m_data[WIDTH]; } - unsigned int size() const + static constexpr unsigned int size() { return sizeof(m_data); } diff --git a/src/util/spanparsing.cpp b/src/util/spanparsing.cpp index 0f68254f2c..e2e2782bec 100644 --- a/src/util/spanparsing.cpp +++ b/src/util/spanparsing.cpp @@ -34,11 +34,11 @@ Span<const char> Expr(Span<const char>& sp) int level = 0; auto it = sp.begin(); while (it != sp.end()) { - if (*it == '(') { + if (*it == '(' || *it == '{') { ++level; - } else if (level && *it == ')') { + } else if (level && (*it == ')' || *it == '}')) { --level; - } else if (level == 0 && (*it == ')' || *it == ',')) { + } else if (level == 0 && (*it == ')' || *it == '}' || *it == ',')) { break; } ++it; diff --git a/src/util/time.cpp b/src/util/time.cpp index e6f0986a39..eda710b12c 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -124,7 +124,7 @@ int64_t GetTimeMicros() return int64_t{GetSystemTime<std::chrono::microseconds>().count()}; } -int64_t GetSystemTimeInSeconds() +int64_t GetTimeSeconds() { return int64_t{GetSystemTime<std::chrono::seconds>().count()}; } diff --git a/src/util/time.h b/src/util/time.h index 7ebcaaa339..4aee01967d 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -39,7 +39,7 @@ inline double CountSecondsDouble(SecondsDouble t) { return t.count(); } /** * DEPRECATED - * Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable) + * Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable) */ int64_t GetTime(); @@ -48,7 +48,7 @@ int64_t GetTimeMillis(); /** Returns the system time (not mockable) */ int64_t GetTimeMicros(); /** Returns the system time (not mockable) */ -int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable +int64_t GetTimeSeconds(); // Like GetTime(), but not mockable /** * DEPRECATED diff --git a/src/validation.cpp b/src/validation.cpp index 86539ab01f..e6e6aadb17 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1401,8 +1401,9 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew) } // Same as InvalidChainFound, above, except not called directly from InvalidateBlock, -// which does its own setBlockIndexCandidates manageent. -void CChainState::InvalidBlockFound(CBlockIndex *pindex, const BlockValidationState &state) { +// which does its own setBlockIndexCandidates management. +void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) +{ if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { pindex->nStatus |= BLOCK_FAILED_VALID; m_blockman.m_failed_blocks.insert(pindex); @@ -1819,8 +1820,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, // may have let in a block that violates the rule prior to updating the // software, and we would NOT be enforcing the rule here. Fully solving // upgrade from one software version to the next after a consensus rule - // change is potentially tricky and issue-specific (see RewindBlockIndex() - // for one general approach that was used for BIP 141 deployment). + // change is potentially tricky and issue-specific (see NeedsRedownload() + // for one approach that was used for BIP 141 deployment). // Also, currently the rule against blocks more than 2 hours in the future // is enforced in ContextualCheckBlockHeader(); we wouldn't want to // re-enforce that rule here (at least until we make it impossible for @@ -3591,29 +3592,32 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block return true; } -bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock) +bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) { AssertLockNotHeld(cs_main); assert(std::addressof(::ChainstateActive()) == std::addressof(ActiveChainstate())); { CBlockIndex *pindex = nullptr; - if (fNewBlock) *fNewBlock = false; + if (new_block) *new_block = false; BlockValidationState state; // CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race. // Therefore, the following critical section must include the CheckBlock() call as well. LOCK(cs_main); - // Ensure that CheckBlock() passes before calling AcceptBlock, as - // belt-and-suspenders. - bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus()); + // Skipping AcceptBlock() for CheckBlock() failures means that we will never mark a block as invalid if + // CheckBlock() fails. This is protective against consensus failure if there are any unknown forms of block + // malleability that cause CheckBlock() to fail; see e.g. CVE-2012-2459 and + // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-February/016697.html. Because CheckBlock() is + // not very expensive, the anti-DoS benefits of caching failure (of a definitely-invalid block) are not substantial. + bool ret = CheckBlock(*block, state, chainparams.GetConsensus()); if (ret) { // Store to disk - ret = ActiveChainstate().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock); + ret = ActiveChainstate().AcceptBlock(block, state, chainparams, &pindex, force_processing, nullptr, new_block); } if (!ret) { - GetMainSignals().BlockChecked(*pblock, state); + GetMainSignals().BlockChecked(*block, state); return error("%s: AcceptBlock FAILED (%s)", __func__, state.ToString()); } } @@ -3621,7 +3625,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s NotifyHeaderTip(ActiveChainstate()); BlockValidationState state; // Only used to report errors, not invalidity - ignore it - if (!ActiveChainstate().ActivateBestChain(state, chainparams, pblock)) + if (!ActiveChainstate().ActivateBestChain(state, chainparams, block)) return error("%s: ActivateBestChain failed (%s)", __func__, state.ToString()); return true; @@ -5079,24 +5083,20 @@ bool ChainstateManager::PopulateAndValidateSnapshot( LOCK(::cs_main); // Fake various pieces of CBlockIndex state: - // - // - nChainTx: so that we accurately report IBD-to-tip progress - // - nTx: so that LoadBlockIndex() loads assumed-valid CBlockIndex entries - // (among other things) - // - nStatus & BLOCK_OPT_WITNESS: so that RewindBlockIndex() doesn't zealously - // unwind the assumed-valid chain. - // CBlockIndex* index = nullptr; for (int i = 0; i <= snapshot_chainstate.m_chain.Height(); ++i) { index = snapshot_chainstate.m_chain[i]; + // Fake nTx so that LoadBlockIndex() loads assumed-valid CBlockIndex + // entries (among other things) if (!index->nTx) { index->nTx = 1; } + // Fake nChainTx so that GuessVerificationProgress reports accurately index->nChainTx = index->pprev ? index->pprev->nChainTx + index->nTx : 1; - // We need to fake this flag so that CChainState::RewindBlockIndex() - // won't try to rewind the entire assumed-valid chain on startup. + // Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload() + // won't ask to rewind the entire assumed-valid chain on startup. if (index->pprev && ::IsWitnessEnabled(index->pprev, ::Params().GetConsensus())) { index->nStatus |= BLOCK_OPT_WITNESS; } diff --git a/src/validation.h b/src/validation.h index 43e1c5c22e..359a6c779f 100644 --- a/src/validation.h +++ b/src/validation.h @@ -555,7 +555,7 @@ enum class CoinsCacheSizeState * * Anything that is contingent on the current tip of the chain is stored here, * whereas block information and metadata independent of the current tip is - * kept in `BlockMetadataManager`. + * kept in `BlockManager`. */ class CChainState { @@ -970,22 +970,21 @@ public: * block is made active. Note that it does not, however, guarantee that the * specific block passed to it has been checked for validity! * - * If you want to *possibly* get feedback on whether pblock is valid, you must + * If you want to *possibly* get feedback on whether block is valid, you must * install a CValidationInterface (see validationinterface.h) - this will have * its BlockChecked method called whenever *any* block completes validation. * - * Note that we guarantee that either the proof-of-work is valid on pblock, or + * Note that we guarantee that either the proof-of-work is valid on block, or * (and possibly also) BlockChecked will have been called. * - * May not be called in a - * validationinterface callback. + * May not be called in a validationinterface callback. * - * @param[in] pblock The block we want to process. - * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources. - * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call + * @param[in] block The block we want to process. + * @param[in] force_processing Process this block even if unrequested; used for non-network block sources. + * @param[out] new_block A boolean which is set to indicate if the block was first received via this call * @returns If the block was processed, independently of block validity */ - bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main); /** * Process incoming block headers. diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 64ce09d1d1..aca52964ee 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -197,22 +197,14 @@ public: } return result; } - bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) override - { + std::vector<std::string> getAddressReceiveRequests() override { LOCK(m_wallet->cs_wallet); - WalletBatch batch{m_wallet->GetDatabase()}; - return m_wallet->AddDestData(batch, dest, key, value); + return m_wallet->GetAddressReceiveRequests(); } - bool eraseDestData(const CTxDestination& dest, const std::string& key) override - { + bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) override { LOCK(m_wallet->cs_wallet); WalletBatch batch{m_wallet->GetDatabase()}; - return m_wallet->EraseDestData(batch, dest, key); - } - std::vector<std::string> getDestValues(const std::string& prefix) override - { - LOCK(m_wallet->cs_wallet); - return m_wallet->GetDestValues(prefix); + return m_wallet->SetAddressReceiveRequest(batch, dest, id, value); } void lockCoin(const COutPoint& output) override { diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp new file mode 100644 index 0000000000..de81dbf324 --- /dev/null +++ b/src/wallet/receive.cpp @@ -0,0 +1,471 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <consensus/consensus.h> +#include <wallet/receive.h> +#include <wallet/transaction.h> +#include <wallet/wallet.h> + +isminetype CWallet::IsMine(const CTxIn &txin) const +{ + AssertLockHeld(cs_wallet); + std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); + if (mi != mapWallet.end()) + { + const CWalletTx& prev = (*mi).second; + if (txin.prevout.n < prev.tx->vout.size()) + return IsMine(prev.tx->vout[txin.prevout.n]); + } + return ISMINE_NO; +} + +bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const +{ + LOCK(cs_wallet); + + for (const CTxIn& txin : tx.vin) + { + auto mi = mapWallet.find(txin.prevout.hash); + if (mi == mapWallet.end()) + return false; // any unknown inputs can't be from us + + const CWalletTx& prev = (*mi).second; + + if (txin.prevout.n >= prev.tx->vout.size()) + return false; // invalid input! + + if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter)) + return false; + } + return true; +} + +CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const +{ + if (!MoneyRange(txout.nValue)) + throw std::runtime_error(std::string(__func__) + ": value out of range"); + LOCK(cs_wallet); + return ((IsMine(txout) & filter) ? txout.nValue : 0); +} + +CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const +{ + CAmount nCredit = 0; + for (const CTxOut& txout : tx.vout) + { + nCredit += GetCredit(txout, filter); + if (!MoneyRange(nCredit)) + throw std::runtime_error(std::string(__func__) + ": value out of range"); + } + return nCredit; +} + +bool CWallet::IsChange(const CScript& script) const +{ + // TODO: fix handling of 'change' outputs. The assumption is that any + // payment to a script that is ours, but is not in the address book + // is change. That assumption is likely to break when we implement multisignature + // wallets that return change back into a multi-signature-protected address; + // a better way of identifying which outputs are 'the send' and which are + // 'the change' will need to be implemented (maybe extend CWalletTx to remember + // which output, if any, was change). + AssertLockHeld(cs_wallet); + if (IsMine(script)) + { + CTxDestination address; + if (!ExtractDestination(script, address)) + return true; + if (!FindAddressBookEntry(address)) { + return true; + } + } + return false; +} + +bool CWallet::IsChange(const CTxOut& txout) const +{ + return IsChange(txout.scriptPubKey); +} + +CAmount CWallet::GetChange(const CTxOut& txout) const +{ + AssertLockHeld(cs_wallet); + if (!MoneyRange(txout.nValue)) + throw std::runtime_error(std::string(__func__) + ": value out of range"); + return (IsChange(txout) ? txout.nValue : 0); +} + +CAmount CWallet::GetChange(const CTransaction& tx) const +{ + LOCK(cs_wallet); + CAmount nChange = 0; + for (const CTxOut& txout : tx.vout) + { + nChange += GetChange(txout); + if (!MoneyRange(nChange)) + throw std::runtime_error(std::string(__func__) + ": value out of range"); + } + return nChange; +} + +CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const +{ + auto& amount = m_amounts[type]; + if (recalculate || !amount.m_cached[filter]) { + amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter)); + m_is_cache_empty = false; + } + return amount.m_value[filter]; +} + +CAmount CWalletTx::GetCredit(const isminefilter& filter) const +{ + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsImmatureCoinBase()) + return 0; + + CAmount credit = 0; + if (filter & ISMINE_SPENDABLE) { + // GetBalance can assume transactions in mapWallet won't change + credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE); + } + if (filter & ISMINE_WATCH_ONLY) { + credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY); + } + return credit; +} + +CAmount CWalletTx::GetDebit(const isminefilter& filter) const +{ + if (tx->vin.empty()) + return 0; + + CAmount debit = 0; + if (filter & ISMINE_SPENDABLE) { + debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE); + } + if (filter & ISMINE_WATCH_ONLY) { + debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY); + } + return debit; +} + +CAmount CWalletTx::GetChange() const +{ + if (fChangeCached) + return nChangeCached; + nChangeCached = pwallet->GetChange(*tx); + fChangeCached = true; + return nChangeCached; +} + +CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const +{ + if (IsImmatureCoinBase() && IsInMainChain()) { + return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache); + } + + return 0; +} + +CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const +{ + if (IsImmatureCoinBase() && IsInMainChain()) { + return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache); + } + + return 0; +} + +CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const +{ + if (pwallet == nullptr) + return 0; + + // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future). + bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsImmatureCoinBase()) + return 0; + + if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) { + return m_amounts[AVAILABLE_CREDIT].m_value[filter]; + } + + bool allow_used_addresses = (filter & ISMINE_USED) || !pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < tx->vout.size(); i++) + { + if (!pwallet->IsSpent(hashTx, i) && (allow_used_addresses || !pwallet->IsSpentKey(hashTx, i))) { + const CTxOut &txout = tx->vout[i]; + nCredit += pwallet->GetCredit(txout, filter); + if (!MoneyRange(nCredit)) + throw std::runtime_error(std::string(__func__) + " : value out of range"); + } + } + + if (allow_cache) { + m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit); + m_is_cache_empty = false; + } + + return nCredit; +} + +void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived, + std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const +{ + nFee = 0; + listReceived.clear(); + listSent.clear(); + + // Compute fee: + CAmount nDebit = GetDebit(filter); + if (nDebit > 0) // debit>0 means we signed/sent this transaction + { + CAmount nValueOut = tx->GetValueOut(); + nFee = nDebit - nValueOut; + } + + LOCK(pwallet->cs_wallet); + // Sent/received. + for (unsigned int i = 0; i < tx->vout.size(); ++i) + { + const CTxOut& txout = tx->vout[i]; + isminetype fIsMine = pwallet->IsMine(txout); + // Only need to handle txouts if AT LEAST one of these is true: + // 1) they debit from us (sent) + // 2) the output is to us (received) + if (nDebit > 0) + { + // Don't report 'change' txouts + if (pwallet->IsChange(txout)) + continue; + } + else if (!(fIsMine & filter)) + continue; + + // In either case, we need to get the destination address + CTxDestination address; + + if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable()) + { + pwallet->WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", + this->GetHash().ToString()); + address = CNoDestination(); + } + + COutputEntry output = {address, txout.nValue, (int)i}; + + // If we are debited by the transaction, add the output as a "sent" entry + if (nDebit > 0) + listSent.push_back(output); + + // If we are receiving the output, add it as a "received" entry + if (fIsMine & filter) + listReceived.push_back(output); + } + +} + +bool CWallet::IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const +{ + AssertLockHeld(cs_wallet); + // Quick answer in most cases + if (!chain().checkFinalTx(*wtx.tx)) return false; + int nDepth = wtx.GetDepthInMainChain(); + if (nDepth >= 1) return true; + if (nDepth < 0) return false; + // using wtx's cached debit + if (!m_spend_zero_conf_change || !wtx.IsFromMe(ISMINE_ALL)) return false; + + // Don't trust unconfirmed transactions from us unless they are in the mempool. + if (!wtx.InMempool()) return false; + + // Trusted if all inputs are from us and are in the mempool: + for (const CTxIn& txin : wtx.tx->vin) + { + // Transactions not sent by us: not trusted + const CWalletTx* parent = GetWalletTx(txin.prevout.hash); + if (parent == nullptr) return false; + const CTxOut& parentOut = parent->tx->vout[txin.prevout.n]; + // Check that this specific input being spent is trusted + if (IsMine(parentOut) != ISMINE_SPENDABLE) return false; + // If we've already trusted this parent, continue + if (trusted_parents.count(parent->GetHash())) continue; + // Recurse to check that the parent is also trusted + if (!IsTrusted(*parent, trusted_parents)) return false; + trusted_parents.insert(parent->GetHash()); + } + return true; +} + +bool CWalletTx::IsTrusted() const +{ + std::set<uint256> trusted_parents; + LOCK(pwallet->cs_wallet); + return pwallet->IsTrusted(*this, trusted_parents); +} + +CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) const +{ + Balance ret; + isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED; + { + LOCK(cs_wallet); + std::set<uint256> trusted_parents; + for (const auto& entry : mapWallet) + { + const CWalletTx& wtx = entry.second; + const bool is_trusted{IsTrusted(wtx, trusted_parents)}; + const int tx_depth{wtx.GetDepthInMainChain()}; + const CAmount tx_credit_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)}; + const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)}; + if (is_trusted && tx_depth >= min_depth) { + ret.m_mine_trusted += tx_credit_mine; + ret.m_watchonly_trusted += tx_credit_watchonly; + } + if (!is_trusted && tx_depth == 0 && wtx.InMempool()) { + ret.m_mine_untrusted_pending += tx_credit_mine; + ret.m_watchonly_untrusted_pending += tx_credit_watchonly; + } + ret.m_mine_immature += wtx.GetImmatureCredit(); + ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(); + } + } + return ret; +} + +std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() const +{ + std::map<CTxDestination, CAmount> balances; + + { + LOCK(cs_wallet); + std::set<uint256> trusted_parents; + for (const auto& walletEntry : mapWallet) + { + const CWalletTx& wtx = walletEntry.second; + + if (!IsTrusted(wtx, trusted_parents)) + continue; + + if (wtx.IsImmatureCoinBase()) + continue; + + int nDepth = wtx.GetDepthInMainChain(); + if (nDepth < (wtx.IsFromMe(ISMINE_ALL) ? 0 : 1)) + continue; + + for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) + { + CTxDestination addr; + if (!IsMine(wtx.tx->vout[i])) + continue; + if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr)) + continue; + + CAmount n = IsSpent(walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue; + balances[addr] += n; + } + } + } + + return balances; +} + +std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() const +{ + AssertLockHeld(cs_wallet); + std::set< std::set<CTxDestination> > groupings; + std::set<CTxDestination> grouping; + + for (const auto& walletEntry : mapWallet) + { + const CWalletTx& wtx = walletEntry.second; + + if (wtx.tx->vin.size() > 0) + { + bool any_mine = false; + // group all input addresses with each other + for (const CTxIn& txin : wtx.tx->vin) + { + CTxDestination address; + if(!IsMine(txin)) /* If this input isn't mine, ignore it */ + continue; + if(!ExtractDestination(mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address)) + continue; + grouping.insert(address); + any_mine = true; + } + + // group change with input addresses + if (any_mine) + { + for (const CTxOut& txout : wtx.tx->vout) + if (IsChange(txout)) + { + CTxDestination txoutAddr; + if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) + continue; + grouping.insert(txoutAddr); + } + } + if (grouping.size() > 0) + { + groupings.insert(grouping); + grouping.clear(); + } + } + + // group lone addrs by themselves + for (const auto& txout : wtx.tx->vout) + if (IsMine(txout)) + { + CTxDestination address; + if(!ExtractDestination(txout.scriptPubKey, address)) + continue; + grouping.insert(address); + groupings.insert(grouping); + grouping.clear(); + } + } + + std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses + std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it + for (std::set<CTxDestination> _grouping : groupings) + { + // make a set of all the groups hit by this new group + std::set< std::set<CTxDestination>* > hits; + std::map< CTxDestination, std::set<CTxDestination>* >::iterator it; + for (const CTxDestination& address : _grouping) + if ((it = setmap.find(address)) != setmap.end()) + hits.insert((*it).second); + + // merge all hit groups into a new single group and delete old groups + std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping); + for (std::set<CTxDestination>* hit : hits) + { + merged->insert(hit->begin(), hit->end()); + uniqueGroupings.erase(hit); + delete hit; + } + uniqueGroupings.insert(merged); + + // update setmap + for (const CTxDestination& element : *merged) + setmap[element] = merged; + } + + std::set< std::set<CTxDestination> > ret; + for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) + { + ret.insert(*uniqueGrouping); + delete uniqueGrouping; + } + + return ret; +} diff --git a/src/wallet/receive.h b/src/wallet/receive.h new file mode 100644 index 0000000000..8eead32413 --- /dev/null +++ b/src/wallet/receive.h @@ -0,0 +1,20 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_RECEIVE_H +#define BITCOIN_WALLET_RECEIVE_H + +#include <amount.h> +#include <wallet/ismine.h> +#include <wallet/transaction.h> +#include <wallet/wallet.h> + +struct COutputEntry +{ + CTxDestination destination; + CAmount amount; + int vout; +}; + +#endif // BITCOIN_WALLET_RECEIVE_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f270e1ad05..534c974178 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3735,6 +3735,7 @@ public: return obj; } + UniValue operator()(const WitnessV1Taproot& id) const { return UniValue(UniValue::VOBJ); } UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); } }; diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp new file mode 100644 index 0000000000..97fc7acca5 --- /dev/null +++ b/src/wallet/spend.cpp @@ -0,0 +1,978 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <consensus/validation.h> +#include <interfaces/chain.h> +#include <policy/policy.h> +#include <util/check.h> +#include <util/fees.h> +#include <util/moneystr.h> +#include <util/rbf.h> +#include <util/translation.h> +#include <wallet/coincontrol.h> +#include <wallet/fees.h> +#include <wallet/receive.h> +#include <wallet/spend.h> +#include <wallet/transaction.h> +#include <wallet/wallet.h> + +using interfaces::FoundBlock; + +static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100}; + +std::string COutput::ToString() const +{ + return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue)); +} + +int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig) +{ + CMutableTransaction txn; + txn.vin.push_back(CTxIn(COutPoint())); + if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) { + return -1; + } + return GetVirtualTransactionInputSize(txn.vin[0]); +} + +// txouts needs to be in the order of tx.vin +TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig) +{ + CMutableTransaction txNew(tx); + if (!wallet->DummySignTx(txNew, txouts, use_max_sig)) { + return TxSize{-1, -1}; + } + CTransaction ctx(txNew); + int64_t vsize = GetVirtualTransactionSize(ctx); + int64_t weight = GetTransactionWeight(ctx); + return TxSize{vsize, weight}; +} + +TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig) +{ + std::vector<CTxOut> txouts; + for (const CTxIn& input : tx.vin) { + const auto mi = wallet->mapWallet.find(input.prevout.hash); + // Can not estimate size without knowing the input details + if (mi == wallet->mapWallet.end()) { + return TxSize{-1, -1}; + } + assert(input.prevout.n < mi->second.tx->vout.size()); + txouts.emplace_back(mi->second.tx->vout[input.prevout.n]); + } + return CalculateMaximumSignedTxSize(tx, wallet, txouts, use_max_sig); +} + +void CWallet::AvailableCoins(std::vector<COutput>& vCoins, const CCoinControl* coinControl, const CAmount& nMinimumAmount, const CAmount& nMaximumAmount, const CAmount& nMinimumSumAmount, const uint64_t nMaximumCount) const +{ + AssertLockHeld(cs_wallet); + + vCoins.clear(); + CAmount nTotal = 0; + // Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where + // a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses + bool allow_used_addresses = !IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) || (coinControl && !coinControl->m_avoid_address_reuse); + const int min_depth = {coinControl ? coinControl->m_min_depth : DEFAULT_MIN_DEPTH}; + const int max_depth = {coinControl ? coinControl->m_max_depth : DEFAULT_MAX_DEPTH}; + const bool only_safe = {coinControl ? !coinControl->m_include_unsafe_inputs : true}; + + std::set<uint256> trusted_parents; + for (const auto& entry : mapWallet) + { + const uint256& wtxid = entry.first; + const CWalletTx& wtx = entry.second; + + if (!chain().checkFinalTx(*wtx.tx)) { + continue; + } + + if (wtx.IsImmatureCoinBase()) + continue; + + int nDepth = wtx.GetDepthInMainChain(); + if (nDepth < 0) + continue; + + // We should not consider coins which aren't at least in our mempool + // It's possible for these to be conflicted via ancestors which we may never be able to detect + if (nDepth == 0 && !wtx.InMempool()) + continue; + + bool safeTx = IsTrusted(wtx, trusted_parents); + + // We should not consider coins from transactions that are replacing + // other transactions. + // + // Example: There is a transaction A which is replaced by bumpfee + // transaction B. In this case, we want to prevent creation of + // a transaction B' which spends an output of B. + // + // Reason: If transaction A were initially confirmed, transactions B + // and B' would no longer be valid, so the user would have to create + // a new transaction C to replace B'. However, in the case of a + // one-block reorg, transactions B' and C might BOTH be accepted, + // when the user only wanted one of them. Specifically, there could + // be a 1-block reorg away from the chain where transactions A and C + // were accepted to another chain where B, B', and C were all + // accepted. + if (nDepth == 0 && wtx.mapValue.count("replaces_txid")) { + safeTx = false; + } + + // Similarly, we should not consider coins from transactions that + // have been replaced. In the example above, we would want to prevent + // creation of a transaction A' spending an output of A, because if + // transaction B were initially confirmed, conflicting with A and + // A', we wouldn't want to the user to create a transaction D + // intending to replace A', but potentially resulting in a scenario + // where A, A', and D could all be accepted (instead of just B and + // D, or just A and A' like the user would want). + if (nDepth == 0 && wtx.mapValue.count("replaced_by_txid")) { + safeTx = false; + } + + if (only_safe && !safeTx) { + continue; + } + + if (nDepth < min_depth || nDepth > max_depth) { + continue; + } + + for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { + // Only consider selected coins if add_inputs is false + if (coinControl && !coinControl->m_add_inputs && !coinControl->IsSelected(COutPoint(entry.first, i))) { + continue; + } + + if (wtx.tx->vout[i].nValue < nMinimumAmount || wtx.tx->vout[i].nValue > nMaximumAmount) + continue; + + if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i))) + continue; + + if (IsLockedCoin(entry.first, i)) + continue; + + if (IsSpent(wtxid, i)) + continue; + + isminetype mine = IsMine(wtx.tx->vout[i]); + + if (mine == ISMINE_NO) { + continue; + } + + if (!allow_used_addresses && IsSpentKey(wtxid, i)) { + continue; + } + + std::unique_ptr<SigningProvider> provider = GetSolvingProvider(wtx.tx->vout[i].scriptPubKey); + + bool solvable = provider ? IsSolvable(*provider, wtx.tx->vout[i].scriptPubKey) : false; + bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable)); + + vCoins.push_back(COutput(&wtx, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly))); + + // Checks the sum amount of all UTXO's. + if (nMinimumSumAmount != MAX_MONEY) { + nTotal += wtx.tx->vout[i].nValue; + + if (nTotal >= nMinimumSumAmount) { + return; + } + } + + // Checks the maximum number of UTXO's. + if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) { + return; + } + } + } +} + +CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const +{ + LOCK(cs_wallet); + + CAmount balance = 0; + std::vector<COutput> vCoins; + AvailableCoins(vCoins, coinControl); + for (const COutput& out : vCoins) { + if (out.fSpendable) { + balance += out.tx->tx->vout[out.i].nValue; + } + } + return balance; +} + +const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int output) const +{ + AssertLockHeld(cs_wallet); + const CTransaction* ptx = &tx; + int n = output; + while (IsChange(ptx->vout[n]) && ptx->vin.size() > 0) { + const COutPoint& prevout = ptx->vin[0].prevout; + auto it = mapWallet.find(prevout.hash); + if (it == mapWallet.end() || it->second.tx->vout.size() <= prevout.n || + !IsMine(it->second.tx->vout[prevout.n])) { + break; + } + ptx = it->second.tx.get(); + n = prevout.n; + } + return ptx->vout[n]; +} + +std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const +{ + AssertLockHeld(cs_wallet); + + std::map<CTxDestination, std::vector<COutput>> result; + std::vector<COutput> availableCoins; + + AvailableCoins(availableCoins); + + for (const COutput& coin : availableCoins) { + CTxDestination address; + if ((coin.fSpendable || (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.fSolvable)) && + ExtractDestination(FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, address)) { + result[address].emplace_back(std::move(coin)); + } + } + + std::vector<COutPoint> lockedCoins; + ListLockedCoins(lockedCoins); + // Include watch-only for LegacyScriptPubKeyMan wallets without private keys + const bool include_watch_only = GetLegacyScriptPubKeyMan() && IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + const isminetype is_mine_filter = include_watch_only ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE; + for (const COutPoint& output : lockedCoins) { + auto it = mapWallet.find(output.hash); + if (it != mapWallet.end()) { + int depth = it->second.GetDepthInMainChain(); + if (depth >= 0 && output.n < it->second.tx->vout.size() && + IsMine(it->second.tx->vout[output.n]) == is_mine_filter + ) { + CTxDestination address; + if (ExtractDestination(FindNonChangeParentOutput(*it->second.tx, output.n).scriptPubKey, address)) { + result[address].emplace_back( + &it->second, output.n, depth, true /* spendable */, true /* solvable */, false /* safe */); + } + } + } + } + + return result; +} + +std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only) const +{ + std::vector<OutputGroup> groups_out; + + if (!coin_sel_params.m_avoid_partial_spends) { + // Allowing partial spends means no grouping. Each COutput gets its own OutputGroup. + for (const COutput& output : outputs) { + // Skip outputs we cannot spend + if (!output.fSpendable) continue; + + size_t ancestors, descendants; + chain().getTransactionAncestry(output.tx->GetHash(), ancestors, descendants); + CInputCoin input_coin = output.GetInputCoin(); + + // Make an OutputGroup containing just this output + OutputGroup group{coin_sel_params}; + group.Insert(input_coin, output.nDepth, output.tx->IsFromMe(ISMINE_ALL), ancestors, descendants, positive_only); + + // Check the OutputGroup's eligibility. Only add the eligible ones. + if (positive_only && group.GetSelectionAmount() <= 0) continue; + if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter)) groups_out.push_back(group); + } + return groups_out; + } + + // We want to combine COutputs that have the same scriptPubKey into single OutputGroups + // except when there are more than OUTPUT_GROUP_MAX_ENTRIES COutputs grouped in an OutputGroup. + // To do this, we maintain a map where the key is the scriptPubKey and the value is a vector of OutputGroups. + // For each COutput, we check if the scriptPubKey is in the map, and if it is, the COutput's CInputCoin is added + // to the last OutputGroup in the vector for the scriptPubKey. When the last OutputGroup has + // OUTPUT_GROUP_MAX_ENTRIES CInputCoins, a new OutputGroup is added to the end of the vector. + std::map<CScript, std::vector<OutputGroup>> spk_to_groups_map; + for (const auto& output : outputs) { + // Skip outputs we cannot spend + if (!output.fSpendable) continue; + + size_t ancestors, descendants; + chain().getTransactionAncestry(output.tx->GetHash(), ancestors, descendants); + CInputCoin input_coin = output.GetInputCoin(); + CScript spk = input_coin.txout.scriptPubKey; + + std::vector<OutputGroup>& groups = spk_to_groups_map[spk]; + + if (groups.size() == 0) { + // No OutputGroups for this scriptPubKey yet, add one + groups.emplace_back(coin_sel_params); + } + + // Get the last OutputGroup in the vector so that we can add the CInputCoin to it + // A pointer is used here so that group can be reassigned later if it is full. + OutputGroup* group = &groups.back(); + + // Check if this OutputGroup is full. We limit to OUTPUT_GROUP_MAX_ENTRIES when using -avoidpartialspends + // to avoid surprising users with very high fees. + if (group->m_outputs.size() >= OUTPUT_GROUP_MAX_ENTRIES) { + // The last output group is full, add a new group to the vector and use that group for the insertion + groups.emplace_back(coin_sel_params); + group = &groups.back(); + } + + // Add the input_coin to group + group->Insert(input_coin, output.nDepth, output.tx->IsFromMe(ISMINE_ALL), ancestors, descendants, positive_only); + } + + // Now we go through the entire map and pull out the OutputGroups + for (const auto& spk_and_groups_pair: spk_to_groups_map) { + const std::vector<OutputGroup>& groups_per_spk= spk_and_groups_pair.second; + + // Go through the vector backwards. This allows for the first item we deal with being the partial group. + for (auto group_it = groups_per_spk.rbegin(); group_it != groups_per_spk.rend(); group_it++) { + const OutputGroup& group = *group_it; + + // Don't include partial groups if there are full groups too and we don't want partial groups + if (group_it == groups_per_spk.rbegin() && groups_per_spk.size() > 1 && !filter.m_include_partial_groups) { + continue; + } + + // Check the OutputGroup's eligibility. Only add the eligible ones. + if (positive_only && group.GetSelectionAmount() <= 0) continue; + if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter)) groups_out.push_back(group); + } + } + + return groups_out; +} + +bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, + std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params) const +{ + setCoinsRet.clear(); + nValueRet = 0; + + // Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output. + std::vector<OutputGroup> positive_groups = GroupOutputs(coins, coin_selection_params, eligibility_filter, true /* positive_only */); + if (SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change, setCoinsRet, nValueRet)) { + return true; + } + // The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here. + std::vector<OutputGroup> all_groups = GroupOutputs(coins, coin_selection_params, eligibility_filter, false /* positive_only */); + // While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output. + // So we need to include that for KnapsackSolver as well, as we are expecting to create a change output. + return KnapsackSolver(nTargetValue + coin_selection_params.m_change_fee, all_groups, setCoinsRet, nValueRet); +} + +bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params) const +{ + std::vector<COutput> vCoins(vAvailableCoins); + CAmount value_to_select = nTargetValue; + + // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) + if (coin_control.HasSelected() && !coin_control.fAllowOtherInputs) + { + for (const COutput& out : vCoins) + { + if (!out.fSpendable) + continue; + nValueRet += out.tx->tx->vout[out.i].nValue; + setCoinsRet.insert(out.GetInputCoin()); + } + return (nValueRet >= nTargetValue); + } + + // calculate value from preset inputs and store them + std::set<CInputCoin> setPresetCoins; + CAmount nValueFromPresetInputs = 0; + + std::vector<COutPoint> vPresetInputs; + coin_control.ListSelected(vPresetInputs); + for (const COutPoint& outpoint : vPresetInputs) + { + std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); + if (it != mapWallet.end()) + { + const CWalletTx& wtx = it->second; + // Clearly invalid input, fail + if (wtx.tx->vout.size() <= outpoint.n) { + return false; + } + // Just to calculate the marginal byte size + CInputCoin coin(wtx.tx, outpoint.n, wtx.GetSpendSize(outpoint.n, false)); + nValueFromPresetInputs += coin.txout.nValue; + if (coin.m_input_bytes <= 0) { + return false; // Not solvable, can't estimate size for fee + } + coin.effective_value = coin.txout.nValue - coin_selection_params.m_effective_feerate.GetFee(coin.m_input_bytes); + if (coin_selection_params.m_subtract_fee_outputs) { + value_to_select -= coin.txout.nValue; + } else { + value_to_select -= coin.effective_value; + } + setPresetCoins.insert(coin); + } else { + return false; // TODO: Allow non-wallet inputs + } + } + + // remove preset inputs from vCoins so that Coin Selection doesn't pick them. + for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coin_control.HasSelected();) + { + if (setPresetCoins.count(it->GetInputCoin())) + it = vCoins.erase(it); + else + ++it; + } + + unsigned int limit_ancestor_count = 0; + unsigned int limit_descendant_count = 0; + chain().getPackageLimits(limit_ancestor_count, limit_descendant_count); + const size_t max_ancestors = (size_t)std::max<int64_t>(1, limit_ancestor_count); + const size_t max_descendants = (size_t)std::max<int64_t>(1, limit_descendant_count); + const bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS); + + // form groups from remaining coins; note that preset coins will not + // automatically have their associated (same address) coins included + if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) { + // Cases where we have 101+ outputs all pointing to the same destination may result in + // privacy leaks as they will potentially be deterministically sorted. We solve that by + // explicitly shuffling the outputs before processing + Shuffle(vCoins.begin(), vCoins.end(), FastRandomContext()); + } + + // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the + // transaction at a target feerate. If an attempt fails, more attempts may be made using a more + // permissive CoinEligibilityFilter. + const bool res = [&] { + // Pre-selected inputs already cover the target amount. + if (value_to_select <= 0) return true; + + // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six + // confirmations on outputs received from other wallets and only spend confirmed change. + if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true; + if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true; + + // Fall back to using zero confirmation change (but with as few ancestors in the mempool as + // possible) if we cannot fund the transaction otherwise. + if (m_spend_zero_conf_change) { + if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true; + if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), + vCoins, setCoinsRet, nValueRet, coin_selection_params)) { + return true; + } + if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), + vCoins, setCoinsRet, nValueRet, coin_selection_params)) { + return true; + } + // If partial groups are allowed, relax the requirement of spending OutputGroups (groups + // of UTXOs sent to the same address, which are obviously controlled by a single wallet) + // in their entirety. + if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), + vCoins, setCoinsRet, nValueRet, coin_selection_params)) { + return true; + } + // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs + // received from other wallets. + if (coin_control.m_include_unsafe_inputs + && SelectCoinsMinConf(value_to_select, + CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), + vCoins, setCoinsRet, nValueRet, coin_selection_params)) { + return true; + } + // Try with unlimited ancestors/descendants. The transaction will still need to meet + // mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but + // OutputGroups use heuristics that may overestimate ancestor/descendant counts. + if (!fRejectLongChains && SelectCoinsMinConf(value_to_select, + CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */), + vCoins, setCoinsRet, nValueRet, coin_selection_params)) { + return true; + } + } + // Coin Selection failed. + return false; + }(); + + // SelectCoinsMinConf clears setCoinsRet, so add the preset inputs from coin_control to the coinset + util::insert(setCoinsRet, setPresetCoins); + + // add preset inputs to the total value selected + nValueRet += nValueFromPresetInputs; + + return res; +} + +static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256& block_hash) +{ + if (chain.isInitialBlockDownload()) { + return false; + } + constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds + int64_t block_time; + CHECK_NONFATAL(chain.findBlock(block_hash, FoundBlock().time(block_time))); + if (block_time < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) { + return false; + } + return true; +} + +/** + * Return a height-based locktime for new transactions (uses the height of the + * current chain tip unless we are not synced with the current chain + */ +static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uint256& block_hash, int block_height) +{ + uint32_t locktime; + // Discourage fee sniping. + // + // For a large miner the value of the transactions in the best block and + // the mempool can exceed the cost of deliberately attempting to mine two + // blocks to orphan the current best block. By setting nLockTime such that + // only the next block can include the transaction, we discourage this + // practice as the height restricted and limited blocksize gives miners + // considering fee sniping fewer options for pulling off this attack. + // + // A simple way to think about this is from the wallet's point of view we + // always want the blockchain to move forward. By setting nLockTime this + // way we're basically making the statement that we only want this + // transaction to appear in the next block; we don't want to potentially + // encourage reorgs by allowing transactions to appear at lower heights + // than the next block in forks of the best chain. + // + // Of course, the subsidy is high enough, and transaction volume low + // enough, that fee sniping isn't a problem yet, but by implementing a fix + // now we ensure code won't be written that makes assumptions about + // nLockTime that preclude a fix later. + if (IsCurrentForAntiFeeSniping(chain, block_hash)) { + locktime = block_height; + + // Secondly occasionally randomly pick a nLockTime even further back, so + // that transactions that are delayed after signing for whatever reason, + // e.g. high-latency mix networks and some CoinJoin implementations, have + // better privacy. + if (GetRandInt(10) == 0) + locktime = std::max(0, (int)locktime - GetRandInt(100)); + } else { + // If our chain is lagging behind, we can't discourage fee sniping nor help + // the privacy of high-latency transactions. To avoid leaking a potentially + // unique "nLockTime fingerprint", set nLockTime to a constant. + locktime = 0; + } + assert(locktime < LOCKTIME_THRESHOLD); + return locktime; +} + +bool CWallet::CreateTransactionInternal( + const std::vector<CRecipient>& vecSend, + CTransactionRef& tx, + CAmount& nFeeRet, + int& nChangePosInOut, + bilingual_str& error, + const CCoinControl& coin_control, + FeeCalculation& fee_calc_out, + bool sign) +{ + CAmount nValue = 0; + const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend); + ReserveDestination reservedest(this, change_type); + unsigned int nSubtractFeeFromAmount = 0; + for (const auto& recipient : vecSend) + { + if (nValue < 0 || recipient.nAmount < 0) + { + error = _("Transaction amounts must not be negative"); + return false; + } + nValue += recipient.nAmount; + + if (recipient.fSubtractFeeFromAmount) + nSubtractFeeFromAmount++; + } + if (vecSend.empty()) + { + error = _("Transaction must have at least one recipient"); + return false; + } + + CMutableTransaction txNew; + FeeCalculation feeCalc; + TxSize tx_sizes; + int nBytes; + { + std::set<CInputCoin> setCoins; + LOCK(cs_wallet); + txNew.nLockTime = GetLocktimeForNewTransaction(chain(), GetLastBlockHash(), GetLastBlockHeight()); + { + std::vector<COutput> vAvailableCoins; + AvailableCoins(vAvailableCoins, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0); + CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy + coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends; + + // Create change script that will be used if we need change + // TODO: pass in scriptChange instead of reservedest so + // change transaction isn't always pay-to-bitcoin-address + CScript scriptChange; + + // coin control: send change to custom address + if (!std::get_if<CNoDestination>(&coin_control.destChange)) { + scriptChange = GetScriptForDestination(coin_control.destChange); + } else { // no coin control: send change to newly generated address + // Note: We use a new key here to keep it from being obvious which side is the change. + // The drawback is that by not reusing a previous key, the change may be lost if a + // backup is restored, if the backup doesn't have the new private key for the change. + // If we reused the old key, it would be possible to add code to look for and + // rediscover unknown transactions that were written with keys of ours to recover + // post-backup change. + + // Reserve a new key pair from key pool. If it fails, provide a dummy + // destination in case we don't need change. + CTxDestination dest; + if (!reservedest.GetReservedDestination(dest, true)) { + error = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first."); + } + scriptChange = GetScriptForDestination(dest); + // A valid destination implies a change script (and + // vice-versa). An empty change script will abort later, if the + // change keypool ran out, but change is required. + CHECK_NONFATAL(IsValidDestination(dest) != scriptChange.empty()); + } + CTxOut change_prototype_txout(0, scriptChange); + coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout); + + // Get size of spending the change output + int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, this); + // If the wallet doesn't know how to sign change output, assume p2sh-p2wpkh + // as lower-bound to allow BnB to do it's thing + if (change_spend_size == -1) { + coin_selection_params.change_spend_size = DUMMY_NESTED_P2WPKH_INPUT_SIZE; + } else { + coin_selection_params.change_spend_size = (size_t)change_spend_size; + } + + // Set discard feerate + coin_selection_params.m_discard_feerate = GetDiscardRate(*this); + + // Get the fee rate to use effective values in coin selection + coin_selection_params.m_effective_feerate = GetMinimumFeeRate(*this, coin_control, &feeCalc); + // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly + // provided one + if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) { + error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB)); + return false; + } + if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) { + // eventually allow a fallback fee + error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee."); + return false; + } + + // Get long term estimate + CCoinControl cc_temp; + cc_temp.m_confirm_target = chain().estimateMaxBlocks(); + coin_selection_params.m_long_term_feerate = GetMinimumFeeRate(*this, cc_temp, nullptr); + + // Calculate the cost of change + // Cost of change is the cost of creating the change output + cost of spending the change output in the future. + // For creating the change output now, we use the effective feerate. + // For spending the change output in the future, we use the discard feerate for now. + // So cost of change = (change output size * effective feerate) + (size of spending change output * discard feerate) + coin_selection_params.m_change_fee = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size); + coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_change_fee; + + coin_selection_params.m_subtract_fee_outputs = nSubtractFeeFromAmount != 0; // If we are doing subtract fee from recipient, don't use effective values + + // vouts to the payees + if (!coin_selection_params.m_subtract_fee_outputs) { + coin_selection_params.tx_noinputs_size = 11; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 output count, 1 witness overhead (dummy, flag, stack size) + } + for (const auto& recipient : vecSend) + { + CTxOut txout(recipient.nAmount, recipient.scriptPubKey); + + // Include the fee cost for outputs. + if (!coin_selection_params.m_subtract_fee_outputs) { + coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION); + } + + if (IsDust(txout, chain().relayDustFee())) + { + error = _("Transaction amount too small"); + return false; + } + txNew.vout.push_back(txout); + } + + // Include the fees for things that aren't inputs, excluding the change output + const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size); + CAmount nValueToSelect = nValue + not_input_fees; + + // Choose coins to use + CAmount inputs_sum = 0; + setCoins.clear(); + if (!SelectCoins(vAvailableCoins, /* nTargetValue */ nValueToSelect, setCoins, inputs_sum, coin_control, coin_selection_params)) + { + error = _("Insufficient funds"); + return false; + } + + // Always make a change output + // We will reduce the fee from this change output later, and remove the output if it is too small. + const CAmount change_and_fee = inputs_sum - nValue; + assert(change_and_fee >= 0); + CTxOut newTxOut(change_and_fee, scriptChange); + + if (nChangePosInOut == -1) + { + // Insert change txn at random position: + nChangePosInOut = GetRandInt(txNew.vout.size()+1); + } + else if ((unsigned int)nChangePosInOut > txNew.vout.size()) + { + error = _("Change index out of range"); + return false; + } + + assert(nChangePosInOut != -1); + auto change_position = txNew.vout.insert(txNew.vout.begin() + nChangePosInOut, newTxOut); + + // Dummy fill vin for maximum size estimation + // + for (const auto& coin : setCoins) { + txNew.vin.push_back(CTxIn(coin.outpoint,CScript())); + } + + // Calculate the transaction fee + tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly); + nBytes = tx_sizes.vsize; + if (nBytes < 0) { + error = _("Signing transaction failed"); + return false; + } + nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes); + + // Subtract fee from the change output if not subtrating it from recipient outputs + CAmount fee_needed = nFeeRet; + if (nSubtractFeeFromAmount == 0) { + change_position->nValue -= fee_needed; + } + + // We want to drop the change to fees if: + // 1. The change output would be dust + // 2. The change is within the (almost) exact match window, i.e. it is less than or equal to the cost of the change output (cost_of_change) + CAmount change_amount = change_position->nValue; + if (IsDust(*change_position, coin_selection_params.m_discard_feerate) || change_amount <= coin_selection_params.m_cost_of_change) + { + nChangePosInOut = -1; + change_amount = 0; + txNew.vout.erase(change_position); + + // Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those + tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly); + nBytes = tx_sizes.vsize; + fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes); + } + + // Update nFeeRet in case fee_needed changed due to dropping the change output + if (fee_needed <= change_and_fee - change_amount) { + nFeeRet = change_and_fee - change_amount; + } + + // Reduce output values for subtractFeeFromAmount + if (nSubtractFeeFromAmount != 0) { + CAmount to_reduce = fee_needed + change_amount - change_and_fee; + int i = 0; + bool fFirst = true; + for (const auto& recipient : vecSend) + { + if (i == nChangePosInOut) { + ++i; + } + CTxOut& txout = txNew.vout[i]; + + if (recipient.fSubtractFeeFromAmount) + { + txout.nValue -= to_reduce / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient + + if (fFirst) // first receiver pays the remainder not divisible by output count + { + fFirst = false; + txout.nValue -= to_reduce % nSubtractFeeFromAmount; + } + + // Error if this output is reduced to be below dust + if (IsDust(txout, chain().relayDustFee())) { + if (txout.nValue < 0) { + error = _("The transaction amount is too small to pay the fee"); + } else { + error = _("The transaction amount is too small to send after the fee has been deducted"); + } + return false; + } + } + ++i; + } + nFeeRet = fee_needed; + } + + // Give up if change keypool ran out and change is required + if (scriptChange.empty() && nChangePosInOut != -1) { + return false; + } + } + + // Shuffle selected coins and fill in final vin + txNew.vin.clear(); + std::vector<CInputCoin> selected_coins(setCoins.begin(), setCoins.end()); + Shuffle(selected_coins.begin(), selected_coins.end(), FastRandomContext()); + + // Note how the sequence number is set to non-maxint so that + // the nLockTime set above actually works. + // + // BIP125 defines opt-in RBF as any nSequence < maxint-1, so + // we use the highest possible value in that range (maxint-2) + // to avoid conflicting with other possible uses of nSequence, + // and in the spirit of "smallest possible change from prior + // behavior." + const uint32_t nSequence = coin_control.m_signal_bip125_rbf.value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); + for (const auto& coin : selected_coins) { + txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence)); + } + + if (sign && !SignTransaction(txNew)) { + error = _("Signing transaction failed"); + return false; + } + + // Return the constructed transaction data. + tx = MakeTransactionRef(std::move(txNew)); + + // Limit size + if ((sign && GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) || + (!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT)) + { + error = _("Transaction too large"); + return false; + } + } + + if (nFeeRet > m_default_max_tx_fee) { + error = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED); + return false; + } + + if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { + // Lastly, ensure this tx will pass the mempool's chain limits + if (!chain().checkChainLimits(tx)) { + error = _("Transaction has too long of a mempool chain"); + return false; + } + } + + // Before we return success, we assume any change key will be used to prevent + // accidental re-use. + reservedest.KeepDestination(); + fee_calc_out = feeCalc; + + WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", + nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, + feeCalc.est.pass.start, feeCalc.est.pass.end, + (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0, + feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool, + feeCalc.est.fail.start, feeCalc.est.fail.end, + (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0, + feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool); + return true; +} + +bool CWallet::CreateTransaction( + const std::vector<CRecipient>& vecSend, + CTransactionRef& tx, + CAmount& nFeeRet, + int& nChangePosInOut, + bilingual_str& error, + const CCoinControl& coin_control, + FeeCalculation& fee_calc_out, + bool sign) +{ + int nChangePosIn = nChangePosInOut; + Assert(!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr) + bool res = CreateTransactionInternal(vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, fee_calc_out, sign); + // try with avoidpartialspends unless it's enabled already + if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) { + CCoinControl tmp_cc = coin_control; + tmp_cc.m_avoid_partial_spends = true; + CAmount nFeeRet2; + CTransactionRef tx2; + int nChangePosInOut2 = nChangePosIn; + bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results + if (CreateTransactionInternal(vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign)) { + // if fee of this alternative one is within the range of the max fee, we use this one + const bool use_aps = nFeeRet2 <= nFeeRet + m_max_aps_fee; + WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n", nFeeRet, nFeeRet2, use_aps ? "grouped" : "non-grouped"); + if (use_aps) { + tx = tx2; + nFeeRet = nFeeRet2; + nChangePosInOut = nChangePosInOut2; + } + } + } + return res; +} + +bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl) +{ + std::vector<CRecipient> vecSend; + + // Turn the txout set into a CRecipient vector. + for (size_t idx = 0; idx < tx.vout.size(); idx++) { + const CTxOut& txOut = tx.vout[idx]; + CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1}; + vecSend.push_back(recipient); + } + + coinControl.fAllowOtherInputs = true; + + for (const CTxIn& txin : tx.vin) { + coinControl.Select(txin.prevout); + } + + // Acquire the locks to prevent races to the new locked unspents between the + // CreateTransaction call and LockCoin calls (when lockUnspents is true). + LOCK(cs_wallet); + + CTransactionRef tx_new; + FeeCalculation fee_calc_out; + if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, fee_calc_out, false)) { + return false; + } + + if (nChangePosInOut != -1) { + tx.vout.insert(tx.vout.begin() + nChangePosInOut, tx_new->vout[nChangePosInOut]); + } + + // Copy output sizes from new transaction; they may have had the fee + // subtracted from them. + for (unsigned int idx = 0; idx < tx.vout.size(); idx++) { + tx.vout[idx].nValue = tx_new->vout[idx].nValue; + } + + // Add new txins while keeping original txin scriptSig/order. + for (const CTxIn& txin : tx_new->vin) { + if (!coinControl.IsSelected(txin.prevout)) { + tx.vin.push_back(txin); + + } + if (lockUnspents) { + LockCoin(txin.prevout); + } + + } + + return true; +} diff --git a/src/wallet/spend.h b/src/wallet/spend.h new file mode 100644 index 0000000000..03f9a7c2b5 --- /dev/null +++ b/src/wallet/spend.h @@ -0,0 +1,64 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_SPEND_H +#define BITCOIN_WALLET_SPEND_H + +#include <wallet/coinselection.h> +#include <wallet/transaction.h> +#include <wallet/wallet.h> + +class COutput +{ +public: + const CWalletTx *tx; + + /** Index in tx->vout. */ + int i; + + /** + * Depth in block chain. + * If > 0: the tx is on chain and has this many confirmations. + * If = 0: the tx is waiting confirmation. + * If < 0: a conflicting tx is on chain and has this many confirmations. */ + int nDepth; + + /** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */ + int nInputBytes; + + /** Whether we have the private keys to spend this output */ + bool fSpendable; + + /** Whether we know how to spend this output, ignoring the lack of keys */ + bool fSolvable; + + /** Whether to use the maximum sized, 72 byte signature when calculating the size of the input spend. This should only be set when watch-only outputs are allowed */ + bool use_max_sig; + + /** + * Whether this output is considered safe to spend. Unconfirmed transactions + * from outside keys and unconfirmed replacement transactions are considered + * unsafe and will not be used to fund new spending transactions. + */ + bool fSafe; + + COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn, bool use_max_sig_in = false) + { + tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1; use_max_sig = use_max_sig_in; + // If known and signable by the given wallet, compute nInputBytes + // Failure will keep this value -1 + if (fSpendable && tx) { + nInputBytes = tx->GetSpendSize(i, use_max_sig); + } + } + + std::string ToString() const; + + inline CInputCoin GetInputCoin() const + { + return CInputCoin(tx->tx, i, nInputBytes); + } +}; + +#endif // BITCOIN_WALLET_SPEND_H diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 34bb29f79f..6a791748b4 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -385,11 +385,11 @@ BOOST_AUTO_TEST_CASE(LoadReceiveRequests) CTxDestination dest = PKHash(); LOCK(m_wallet.cs_wallet); WalletBatch batch{m_wallet.GetDatabase()}; - m_wallet.AddDestData(batch, dest, "misc", "val_misc"); - m_wallet.AddDestData(batch, dest, "rr0", "val_rr0"); - m_wallet.AddDestData(batch, dest, "rr1", "val_rr1"); + m_wallet.SetAddressUsed(batch, dest, true); + m_wallet.SetAddressReceiveRequest(batch, dest, "0", "val_rr0"); + m_wallet.SetAddressReceiveRequest(batch, dest, "1", "val_rr1"); - auto values = m_wallet.GetDestValues("rr"); + auto values = m_wallet.GetAddressReceiveRequests(); BOOST_CHECK_EQUAL(values.size(), 2U); BOOST_CHECK_EQUAL(values[0], "val_rr0"); BOOST_CHECK_EQUAL(values[1], "val_rr1"); diff --git a/src/wallet/transaction.cpp b/src/wallet/transaction.cpp new file mode 100644 index 0000000000..cf98b516f1 --- /dev/null +++ b/src/wallet/transaction.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <wallet/transaction.h> + +bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const +{ + CMutableTransaction tx1 {*this->tx}; + CMutableTransaction tx2 {*_tx.tx}; + for (auto& txin : tx1.vin) txin.scriptSig = CScript(); + for (auto& txin : tx2.vin) txin.scriptSig = CScript(); + return CTransaction(tx1) == CTransaction(tx2); +} + +bool CWalletTx::InMempool() const +{ + return fInMempool; +} + +int64_t CWalletTx::GetTxTime() const +{ + int64_t n = nTimeSmart; + return n ? n : nTimeReceived; +} diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h new file mode 100644 index 0000000000..131faefe0b --- /dev/null +++ b/src/wallet/transaction.h @@ -0,0 +1,358 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_TRANSACTION_H +#define BITCOIN_WALLET_TRANSACTION_H + +#include <amount.h> +#include <primitives/transaction.h> +#include <serialize.h> +#include <wallet/ismine.h> +#include <threadsafety.h> +#include <tinyformat.h> +#include <util/strencodings.h> +#include <util/string.h> + +#include <list> +#include <vector> + +struct COutputEntry; + +typedef std::map<std::string, std::string> mapValue_t; + +//Get the marginal bytes of spending the specified output +int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, bool use_max_sig = false); + +static inline void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue) +{ + if (!mapValue.count("n")) + { + nOrderPos = -1; // TODO: calculate elsewhere + return; + } + nOrderPos = atoi64(mapValue["n"]); +} + +static inline void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue) +{ + if (nOrderPos == -1) + return; + mapValue["n"] = ToString(nOrderPos); +} + +/** Legacy class used for deserializing vtxPrev for backwards compatibility. + * vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3, + * but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs. + * These need to get deserialized for field alignment when deserializing + * a CWalletTx, but the deserialized values are discarded.**/ +class CMerkleTx +{ +public: + template<typename Stream> + void Unserialize(Stream& s) + { + CTransactionRef tx; + uint256 hashBlock; + std::vector<uint256> vMerkleBranch; + int nIndex; + + s >> tx >> hashBlock >> vMerkleBranch >> nIndex; + } +}; + +/** + * A transaction with a bunch of additional info that only the owner cares about. + * It includes any unrecorded transactions needed to link it back to the block chain. + */ +class CWalletTx +{ +private: + const CWallet* const pwallet; + + /** Constant used in hashBlock to indicate tx has been abandoned, only used at + * serialization/deserialization to avoid ambiguity with conflicted. + */ + static constexpr const uint256& ABANDON_HASH = uint256::ONE; + +public: + /** + * Key/value map with information about the transaction. + * + * The following keys can be read and written through the map and are + * serialized in the wallet database: + * + * "comment", "to" - comment strings provided to sendtoaddress, + * and sendmany wallet RPCs + * "replaces_txid" - txid (as HexStr) of transaction replaced by + * bumpfee on transaction created by bumpfee + * "replaced_by_txid" - txid (as HexStr) of transaction created by + * bumpfee on transaction replaced by bumpfee + * "from", "message" - obsolete fields that could be set in UI prior to + * 2011 (removed in commit 4d9b223) + * + * The following keys are serialized in the wallet database, but shouldn't + * be read or written through the map (they will be temporarily added and + * removed from the map during serialization): + * + * "fromaccount" - serialized strFromAccount value + * "n" - serialized nOrderPos value + * "timesmart" - serialized nTimeSmart value + * "spent" - serialized vfSpent value that existed prior to + * 2014 (removed in commit 93a18a3) + */ + mapValue_t mapValue; + std::vector<std::pair<std::string, std::string> > vOrderForm; + unsigned int fTimeReceivedIsTxTime; + unsigned int nTimeReceived; //!< time received by this node + /** + * Stable timestamp that never changes, and reflects the order a transaction + * was added to the wallet. Timestamp is based on the block time for a + * transaction added as part of a block, or else the time when the + * transaction was received if it wasn't part of a block, with the timestamp + * adjusted in both cases so timestamp order matches the order transactions + * were added to the wallet. More details can be found in + * CWallet::ComputeTimeSmart(). + */ + unsigned int nTimeSmart; + /** + * From me flag is set to 1 for transactions that were created by the wallet + * on this bitcoin node, and set to 0 for transactions that were created + * externally and came in through the network or sendrawtransaction RPC. + */ + bool fFromMe; + int64_t nOrderPos; //!< position in ordered transaction list + std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered; + + // memory only + enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS }; + CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const; + mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]; + /** + * This flag is true if all m_amounts caches are empty. This is particularly + * useful in places where MarkDirty is conditionally called and the + * condition can be expensive and thus can be skipped if the flag is true. + * See MarkDestinationsDirty. + */ + mutable bool m_is_cache_empty{true}; + mutable bool fChangeCached; + mutable bool fInMempool; + mutable CAmount nChangeCached; + + CWalletTx(const CWallet* wallet, CTransactionRef arg) + : pwallet(wallet), + tx(std::move(arg)) + { + Init(); + } + + void Init() + { + mapValue.clear(); + vOrderForm.clear(); + fTimeReceivedIsTxTime = false; + nTimeReceived = 0; + nTimeSmart = 0; + fFromMe = false; + fChangeCached = false; + fInMempool = false; + nChangeCached = 0; + nOrderPos = -1; + m_confirm = Confirmation{}; + } + + CTransactionRef tx; + + /** New transactions start as UNCONFIRMED. At BlockConnected, + * they will transition to CONFIRMED. In case of reorg, at BlockDisconnected, + * they roll back to UNCONFIRMED. If we detect a conflicting transaction at + * block connection, we update conflicted tx and its dependencies as CONFLICTED. + * If tx isn't confirmed and outside of mempool, the user may switch it to ABANDONED + * by using the abandontransaction call. This last status may be override by a CONFLICTED + * or CONFIRMED transition. + */ + enum Status { + UNCONFIRMED, + CONFIRMED, + CONFLICTED, + ABANDONED + }; + + /** Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} + * at which tx has been confirmed. All three are set to 0 if tx is unconfirmed or abandoned. + * Meaning of these fields changes with CONFLICTED state where they instead point to block hash + * and block height of the deepest conflicting tx. + */ + struct Confirmation { + Status status; + int block_height; + uint256 hashBlock; + int nIndex; + Confirmation(Status s = UNCONFIRMED, int b = 0, uint256 h = uint256(), int i = 0) : status(s), block_height(b), hashBlock(h), nIndex(i) {} + }; + + Confirmation m_confirm; + + template<typename Stream> + void Serialize(Stream& s) const + { + mapValue_t mapValueCopy = mapValue; + + mapValueCopy["fromaccount"] = ""; + WriteOrderPos(nOrderPos, mapValueCopy); + if (nTimeSmart) { + mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); + } + + std::vector<uint8_t> dummy_vector1; //!< Used to be vMerkleBranch + std::vector<uint8_t> dummy_vector2; //!< Used to be vtxPrev + bool dummy_bool = false; //!< Used to be fSpent + uint256 serializedHash = isAbandoned() ? ABANDON_HASH : m_confirm.hashBlock; + int serializedIndex = isAbandoned() || isConflicted() ? -1 : m_confirm.nIndex; + s << tx << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool; + } + + template<typename Stream> + void Unserialize(Stream& s) + { + Init(); + + std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch + std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev + bool dummy_bool; //! Used to be fSpent + int serializedIndex; + s >> tx >> m_confirm.hashBlock >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_bool; + + /* At serialization/deserialization, an nIndex == -1 means that hashBlock refers to + * the earliest block in the chain we know this or any in-wallet ancestor conflicts + * with. If nIndex == -1 and hashBlock is ABANDON_HASH, it means transaction is abandoned. + * In same context, an nIndex >= 0 refers to a confirmed transaction (if hashBlock set) or + * unconfirmed one. Older clients interpret nIndex == -1 as unconfirmed for backward + * compatibility (pre-commit 9ac63d6). + */ + if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) { + setAbandoned(); + } else if (serializedIndex == -1) { + setConflicted(); + } else if (!m_confirm.hashBlock.IsNull()) { + m_confirm.nIndex = serializedIndex; + setConfirmed(); + } + + ReadOrderPos(nOrderPos, mapValue); + nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0; + + mapValue.erase("fromaccount"); + mapValue.erase("spent"); + mapValue.erase("n"); + mapValue.erase("timesmart"); + } + + void SetTx(CTransactionRef arg) + { + tx = std::move(arg); + } + + //! make sure balances are recalculated + void MarkDirty() + { + m_amounts[DEBIT].Reset(); + m_amounts[CREDIT].Reset(); + m_amounts[IMMATURE_CREDIT].Reset(); + m_amounts[AVAILABLE_CREDIT].Reset(); + fChangeCached = false; + m_is_cache_empty = true; + } + + //! filter decides which addresses will count towards the debit + CAmount GetDebit(const isminefilter& filter) const; + CAmount GetCredit(const isminefilter& filter) const; + CAmount GetImmatureCredit(bool fUseCache = true) const; + // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct + // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The + // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid + // having to resolve the issue of member access into incomplete type CWallet. + CAmount GetAvailableCredit(bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS; + CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const; + CAmount GetChange() const; + + /** Get the marginal bytes if spending the specified output from this transaction */ + int GetSpendSize(unsigned int out, bool use_max_sig = false) const + { + return CalculateMaximumSignedInputSize(tx->vout[out], pwallet, use_max_sig); + } + + void GetAmounts(std::list<COutputEntry>& listReceived, + std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const; + + bool IsFromMe(const isminefilter& filter) const + { + return (GetDebit(filter) > 0); + } + + /** True if only scriptSigs are different */ + bool IsEquivalentTo(const CWalletTx& tx) const; + + bool InMempool() const; + bool IsTrusted() const; + + int64_t GetTxTime() const; + + /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ + bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay); + + // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct + // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation + // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to + // resolve the issue of member access into incomplete type CWallet. Note + // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" + // in place. + std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; + + /** + * Return depth of transaction in blockchain: + * <0 : conflicts with a transaction this deep in the blockchain + * 0 : in memory pool, waiting to be included in a block + * >=1 : this many blocks deep in the main chain + */ + // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct + // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation + // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to + // resolve the issue of member access into incomplete type CWallet. Note + // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" + // in place. + int GetDepthInMainChain() const NO_THREAD_SAFETY_ANALYSIS; + bool IsInMainChain() const { return GetDepthInMainChain() > 0; } + + /** + * @return number of blocks to maturity for this transaction: + * 0 : is not a coinbase transaction, or is a mature coinbase transaction + * >0 : is a coinbase transaction which matures in this many blocks + */ + int GetBlocksToMaturity() const; + bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; } + void setAbandoned() + { + m_confirm.status = CWalletTx::ABANDONED; + m_confirm.hashBlock = uint256(); + m_confirm.block_height = 0; + m_confirm.nIndex = 0; + } + bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; } + void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; } + bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; } + void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; } + bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; } + void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; } + const uint256& GetHash() const { return tx->GetHash(); } + bool IsCoinBase() const { return tx->IsCoinBase(); } + bool IsImmatureCoinBase() const; + + // Disable copying of CWalletTx objects to prevent bugs where instances get + // copied in and out of the mapWallet map, and fields are updated in the + // wrong copy. + CWalletTx(CWalletTx const &) = delete; + void operator=(CWalletTx const &x) = delete; +}; + +#endif // BITCOIN_WALLET_TRANSACTION_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 10cc65a38e..4b6630de3c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -53,8 +53,6 @@ const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{ }, }; -static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100}; - RecursiveMutex cs_wallets; static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets); static std::list<LoadWalletFn> g_load_wallet_fns GUARDED_BY(cs_wallets); @@ -351,11 +349,6 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin * @{ */ -std::string COutput::ToString() const -{ - return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue)); -} - const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { AssertLockHeld(cs_wallet); @@ -821,12 +814,11 @@ void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned CTxDestination dst; if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) { if (IsMine(dst)) { - if (used && !GetDestData(dst, "used", nullptr)) { - if (AddDestData(batch, dst, "used", "p")) { // p for "present", opposite of absent (null) + if (used != IsAddressUsed(dst)) { + if (used) { tx_destinations.insert(dst); } - } else if (!used && GetDestData(dst, "used", nullptr)) { - EraseDestData(batch, dst, "used"); + SetAddressUsed(batch, dst, used); } } } @@ -842,7 +834,7 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const if (!ExtractDestination(srctx->tx->vout[n].scriptPubKey, dest)) { return false; } - if (GetDestData(dest, "used", nullptr)) { + if (IsAddressUsed(dest)) { return true; } if (IsLegacy()) { @@ -850,15 +842,15 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const assert(spk_man != nullptr); for (const auto& keyid : GetAffectedKeys(srctx->tx->vout[n].scriptPubKey, *spk_man)) { WitnessV0KeyHash wpkh_dest(keyid); - if (GetDestData(wpkh_dest, "used", nullptr)) { + if (IsAddressUsed(wpkh_dest)) { return true; } ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest)); - if (GetDestData(sh_wpkh_dest, "used", nullptr)) { + if (IsAddressUsed(sh_wpkh_dest)) { return true; } PKHash pkh_dest(keyid); - if (GetDestData(pkh_dest, "used", nullptr)) { + if (IsAddressUsed(pkh_dest)) { return true; } } @@ -1283,20 +1275,6 @@ void CWallet::BlockUntilSyncedToCurrentChain() const { chain().waitForNotificationsIfTipChanged(last_block_hash); } - -isminetype CWallet::IsMine(const CTxIn &txin) const -{ - AssertLockHeld(cs_wallet); - std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); - if (mi != mapWallet.end()) - { - const CWalletTx& prev = (*mi).second; - if (txin.prevout.n < prev.tx->vout.size()) - return IsMine(prev.tx->vout[txin.prevout.n]); - } - return ISMINE_NO; -} - // Note that this function doesn't distinguish between a 0-valued input, // and a not-"is mine" (according to the filter) input. CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const @@ -1337,49 +1315,6 @@ isminetype CWallet::IsMine(const CScript& script) const return result; } -CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const -{ - if (!MoneyRange(txout.nValue)) - throw std::runtime_error(std::string(__func__) + ": value out of range"); - LOCK(cs_wallet); - return ((IsMine(txout) & filter) ? txout.nValue : 0); -} - -bool CWallet::IsChange(const CTxOut& txout) const -{ - return IsChange(txout.scriptPubKey); -} - -bool CWallet::IsChange(const CScript& script) const -{ - // TODO: fix handling of 'change' outputs. The assumption is that any - // payment to a script that is ours, but is not in the address book - // is change. That assumption is likely to break when we implement multisignature - // wallets that return change back into a multi-signature-protected address; - // a better way of identifying which outputs are 'the send' and which are - // 'the change' will need to be implemented (maybe extend CWalletTx to remember - // which output, if any, was change). - AssertLockHeld(cs_wallet); - if (IsMine(script)) - { - CTxDestination address; - if (!ExtractDestination(script, address)) - return true; - if (!FindAddressBookEntry(address)) { - return true; - } - } - return false; -} - -CAmount CWallet::GetChange(const CTxOut& txout) const -{ - AssertLockHeld(cs_wallet); - if (!MoneyRange(txout.nValue)) - throw std::runtime_error(std::string(__func__) + ": value out of range"); - return (IsChange(txout) ? txout.nValue : 0); -} - bool CWallet::IsMine(const CTransaction& tx) const { AssertLockHeld(cs_wallet); @@ -1406,52 +1341,6 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co return nDebit; } -bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const -{ - LOCK(cs_wallet); - - for (const CTxIn& txin : tx.vin) - { - auto mi = mapWallet.find(txin.prevout.hash); - if (mi == mapWallet.end()) - return false; // any unknown inputs can't be from us - - const CWalletTx& prev = (*mi).second; - - if (txin.prevout.n >= prev.tx->vout.size()) - return false; // invalid input! - - if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter)) - return false; - } - return true; -} - -CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const -{ - CAmount nCredit = 0; - for (const CTxOut& txout : tx.vout) - { - nCredit += GetCredit(txout, filter); - if (!MoneyRange(nCredit)) - throw std::runtime_error(std::string(__func__) + ": value out of range"); - } - return nCredit; -} - -CAmount CWallet::GetChange(const CTransaction& tx) const -{ - LOCK(cs_wallet); - CAmount nChange = 0; - for (const CTxOut& txout : tx.vout) - { - nChange += GetChange(txout); - if (!MoneyRange(nChange)) - throw std::runtime_error(std::string(__func__) + ": value out of range"); - } - return nChange; -} - bool CWallet::IsHDEnabled() const { // All Active ScriptPubKeyMans must be HD for this to be true @@ -1531,12 +1420,6 @@ bool CWallet::AddWalletFlags(uint64_t flags) return LoadWalletFlags(flags); } -int64_t CWalletTx::GetTxTime() const -{ - int64_t n = nTimeSmart; - return n ? n : nTimeReceived; -} - // Helper for producing a max-sized low-S low-R signature (eg 71 bytes) // or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig) const @@ -1627,100 +1510,6 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri return true; } -TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig) -{ - std::vector<CTxOut> txouts; - for (const CTxIn& input : tx.vin) { - const auto mi = wallet->mapWallet.find(input.prevout.hash); - // Can not estimate size without knowing the input details - if (mi == wallet->mapWallet.end()) { - return TxSize{-1, -1}; - } - assert(input.prevout.n < mi->second.tx->vout.size()); - txouts.emplace_back(mi->second.tx->vout[input.prevout.n]); - } - return CalculateMaximumSignedTxSize(tx, wallet, txouts, use_max_sig); -} - -// txouts needs to be in the order of tx.vin -TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig) -{ - CMutableTransaction txNew(tx); - if (!wallet->DummySignTx(txNew, txouts, use_max_sig)) { - return TxSize{-1, -1}; - } - CTransaction ctx(txNew); - int64_t vsize = GetVirtualTransactionSize(ctx); - int64_t weight = GetTransactionWeight(ctx); - return TxSize{vsize, weight}; -} - -int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig) -{ - CMutableTransaction txn; - txn.vin.push_back(CTxIn(COutPoint())); - if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) { - return -1; - } - return GetVirtualTransactionInputSize(txn.vin[0]); -} - -void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived, - std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const -{ - nFee = 0; - listReceived.clear(); - listSent.clear(); - - // Compute fee: - CAmount nDebit = GetDebit(filter); - if (nDebit > 0) // debit>0 means we signed/sent this transaction - { - CAmount nValueOut = tx->GetValueOut(); - nFee = nDebit - nValueOut; - } - - LOCK(pwallet->cs_wallet); - // Sent/received. - for (unsigned int i = 0; i < tx->vout.size(); ++i) - { - const CTxOut& txout = tx->vout[i]; - isminetype fIsMine = pwallet->IsMine(txout); - // Only need to handle txouts if AT LEAST one of these is true: - // 1) they debit from us (sent) - // 2) the output is to us (received) - if (nDebit > 0) - { - // Don't report 'change' txouts - if (pwallet->IsChange(txout)) - continue; - } - else if (!(fIsMine & filter)) - continue; - - // In either case, we need to get the destination address - CTxDestination address; - - if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable()) - { - pwallet->WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", - this->GetHash().ToString()); - address = CNoDestination(); - } - - COutputEntry output = {address, txout.nValue, (int)i}; - - // If we are debited by the transaction, add the output as a "sent" entry - if (nDebit > 0) - listSent.push_back(output); - - // If we are receiving the output, add it as a "received" entry - if (fIsMine & filter) - listReceived.push_back(output); - } - -} - /** * Scan active chain for relevant transactions after importing keys. This should * be called whenever new keys are added to the wallet, with the oldest key @@ -1943,165 +1732,6 @@ std::set<uint256> CWalletTx::GetConflicts() const return result; } -CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const -{ - auto& amount = m_amounts[type]; - if (recalculate || !amount.m_cached[filter]) { - amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter)); - m_is_cache_empty = false; - } - return amount.m_value[filter]; -} - -CAmount CWalletTx::GetDebit(const isminefilter& filter) const -{ - if (tx->vin.empty()) - return 0; - - CAmount debit = 0; - if (filter & ISMINE_SPENDABLE) { - debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE); - } - if (filter & ISMINE_WATCH_ONLY) { - debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY); - } - return debit; -} - -CAmount CWalletTx::GetCredit(const isminefilter& filter) const -{ - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsImmatureCoinBase()) - return 0; - - CAmount credit = 0; - if (filter & ISMINE_SPENDABLE) { - // GetBalance can assume transactions in mapWallet won't change - credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE); - } - if (filter & ISMINE_WATCH_ONLY) { - credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY); - } - return credit; -} - -CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const -{ - if (IsImmatureCoinBase() && IsInMainChain()) { - return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache); - } - - return 0; -} - -CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const -{ - if (pwallet == nullptr) - return 0; - - // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future). - bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsImmatureCoinBase()) - return 0; - - if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) { - return m_amounts[AVAILABLE_CREDIT].m_value[filter]; - } - - bool allow_used_addresses = (filter & ISMINE_USED) || !pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < tx->vout.size(); i++) - { - if (!pwallet->IsSpent(hashTx, i) && (allow_used_addresses || !pwallet->IsSpentKey(hashTx, i))) { - const CTxOut &txout = tx->vout[i]; - nCredit += pwallet->GetCredit(txout, filter); - if (!MoneyRange(nCredit)) - throw std::runtime_error(std::string(__func__) + " : value out of range"); - } - } - - if (allow_cache) { - m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit); - m_is_cache_empty = false; - } - - return nCredit; -} - -CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const -{ - if (IsImmatureCoinBase() && IsInMainChain()) { - return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache); - } - - return 0; -} - -CAmount CWalletTx::GetChange() const -{ - if (fChangeCached) - return nChangeCached; - nChangeCached = pwallet->GetChange(*tx); - fChangeCached = true; - return nChangeCached; -} - -bool CWalletTx::InMempool() const -{ - return fInMempool; -} - -bool CWalletTx::IsTrusted() const -{ - std::set<uint256> trusted_parents; - LOCK(pwallet->cs_wallet); - return pwallet->IsTrusted(*this, trusted_parents); -} - -bool CWallet::IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const -{ - AssertLockHeld(cs_wallet); - // Quick answer in most cases - if (!chain().checkFinalTx(*wtx.tx)) return false; - int nDepth = wtx.GetDepthInMainChain(); - if (nDepth >= 1) return true; - if (nDepth < 0) return false; - // using wtx's cached debit - if (!m_spend_zero_conf_change || !wtx.IsFromMe(ISMINE_ALL)) return false; - - // Don't trust unconfirmed transactions from us unless they are in the mempool. - if (!wtx.InMempool()) return false; - - // Trusted if all inputs are from us and are in the mempool: - for (const CTxIn& txin : wtx.tx->vin) - { - // Transactions not sent by us: not trusted - const CWalletTx* parent = GetWalletTx(txin.prevout.hash); - if (parent == nullptr) return false; - const CTxOut& parentOut = parent->tx->vout[txin.prevout.n]; - // Check that this specific input being spent is trusted - if (IsMine(parentOut) != ISMINE_SPENDABLE) return false; - // If we've already trusted this parent, continue - if (trusted_parents.count(parent->GetHash())) continue; - // Recurse to check that the parent is also trusted - if (!IsTrusted(*parent, trusted_parents)) return false; - trusted_parents.insert(parent->GetHash()); - } - return true; -} - -bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const -{ - CMutableTransaction tx1 {*this->tx}; - CMutableTransaction tx2 {*_tx.tx}; - for (auto& txin : tx1.vin) txin.scriptSig = CScript(); - for (auto& txin : tx2.vin) txin.scriptSig = CScript(); - return CTransaction(tx1) == CTransaction(tx2); -} - // Rebroadcast transactions from the wallet. We do this on a random timer // to slightly obfuscate which transactions come from our wallet. // @@ -2162,394 +1792,6 @@ void MaybeResendWalletTxs() * @{ */ - -CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) const -{ - Balance ret; - isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED; - { - LOCK(cs_wallet); - std::set<uint256> trusted_parents; - for (const auto& entry : mapWallet) - { - const CWalletTx& wtx = entry.second; - const bool is_trusted{IsTrusted(wtx, trusted_parents)}; - const int tx_depth{wtx.GetDepthInMainChain()}; - const CAmount tx_credit_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)}; - const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)}; - if (is_trusted && tx_depth >= min_depth) { - ret.m_mine_trusted += tx_credit_mine; - ret.m_watchonly_trusted += tx_credit_watchonly; - } - if (!is_trusted && tx_depth == 0 && wtx.InMempool()) { - ret.m_mine_untrusted_pending += tx_credit_mine; - ret.m_watchonly_untrusted_pending += tx_credit_watchonly; - } - ret.m_mine_immature += wtx.GetImmatureCredit(); - ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(); - } - } - return ret; -} - -CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const -{ - LOCK(cs_wallet); - - CAmount balance = 0; - std::vector<COutput> vCoins; - AvailableCoins(vCoins, coinControl); - for (const COutput& out : vCoins) { - if (out.fSpendable) { - balance += out.tx->tx->vout[out.i].nValue; - } - } - return balance; -} - -void CWallet::AvailableCoins(std::vector<COutput>& vCoins, const CCoinControl* coinControl, const CAmount& nMinimumAmount, const CAmount& nMaximumAmount, const CAmount& nMinimumSumAmount, const uint64_t nMaximumCount) const -{ - AssertLockHeld(cs_wallet); - - vCoins.clear(); - CAmount nTotal = 0; - // Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where - // a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses - bool allow_used_addresses = !IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) || (coinControl && !coinControl->m_avoid_address_reuse); - const int min_depth = {coinControl ? coinControl->m_min_depth : DEFAULT_MIN_DEPTH}; - const int max_depth = {coinControl ? coinControl->m_max_depth : DEFAULT_MAX_DEPTH}; - const bool only_safe = {coinControl ? !coinControl->m_include_unsafe_inputs : true}; - - std::set<uint256> trusted_parents; - for (const auto& entry : mapWallet) - { - const uint256& wtxid = entry.first; - const CWalletTx& wtx = entry.second; - - if (!chain().checkFinalTx(*wtx.tx)) { - continue; - } - - if (wtx.IsImmatureCoinBase()) - continue; - - int nDepth = wtx.GetDepthInMainChain(); - if (nDepth < 0) - continue; - - // We should not consider coins which aren't at least in our mempool - // It's possible for these to be conflicted via ancestors which we may never be able to detect - if (nDepth == 0 && !wtx.InMempool()) - continue; - - bool safeTx = IsTrusted(wtx, trusted_parents); - - // We should not consider coins from transactions that are replacing - // other transactions. - // - // Example: There is a transaction A which is replaced by bumpfee - // transaction B. In this case, we want to prevent creation of - // a transaction B' which spends an output of B. - // - // Reason: If transaction A were initially confirmed, transactions B - // and B' would no longer be valid, so the user would have to create - // a new transaction C to replace B'. However, in the case of a - // one-block reorg, transactions B' and C might BOTH be accepted, - // when the user only wanted one of them. Specifically, there could - // be a 1-block reorg away from the chain where transactions A and C - // were accepted to another chain where B, B', and C were all - // accepted. - if (nDepth == 0 && wtx.mapValue.count("replaces_txid")) { - safeTx = false; - } - - // Similarly, we should not consider coins from transactions that - // have been replaced. In the example above, we would want to prevent - // creation of a transaction A' spending an output of A, because if - // transaction B were initially confirmed, conflicting with A and - // A', we wouldn't want to the user to create a transaction D - // intending to replace A', but potentially resulting in a scenario - // where A, A', and D could all be accepted (instead of just B and - // D, or just A and A' like the user would want). - if (nDepth == 0 && wtx.mapValue.count("replaced_by_txid")) { - safeTx = false; - } - - if (only_safe && !safeTx) { - continue; - } - - if (nDepth < min_depth || nDepth > max_depth) { - continue; - } - - for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { - // Only consider selected coins if add_inputs is false - if (coinControl && !coinControl->m_add_inputs && !coinControl->IsSelected(COutPoint(entry.first, i))) { - continue; - } - - if (wtx.tx->vout[i].nValue < nMinimumAmount || wtx.tx->vout[i].nValue > nMaximumAmount) - continue; - - if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i))) - continue; - - if (IsLockedCoin(entry.first, i)) - continue; - - if (IsSpent(wtxid, i)) - continue; - - isminetype mine = IsMine(wtx.tx->vout[i]); - - if (mine == ISMINE_NO) { - continue; - } - - if (!allow_used_addresses && IsSpentKey(wtxid, i)) { - continue; - } - - std::unique_ptr<SigningProvider> provider = GetSolvingProvider(wtx.tx->vout[i].scriptPubKey); - - bool solvable = provider ? IsSolvable(*provider, wtx.tx->vout[i].scriptPubKey) : false; - bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable)); - - vCoins.push_back(COutput(&wtx, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly))); - - // Checks the sum amount of all UTXO's. - if (nMinimumSumAmount != MAX_MONEY) { - nTotal += wtx.tx->vout[i].nValue; - - if (nTotal >= nMinimumSumAmount) { - return; - } - } - - // Checks the maximum number of UTXO's. - if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) { - return; - } - } - } -} - -std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const -{ - AssertLockHeld(cs_wallet); - - std::map<CTxDestination, std::vector<COutput>> result; - std::vector<COutput> availableCoins; - - AvailableCoins(availableCoins); - - for (const COutput& coin : availableCoins) { - CTxDestination address; - if ((coin.fSpendable || (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.fSolvable)) && - ExtractDestination(FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, address)) { - result[address].emplace_back(std::move(coin)); - } - } - - std::vector<COutPoint> lockedCoins; - ListLockedCoins(lockedCoins); - // Include watch-only for LegacyScriptPubKeyMan wallets without private keys - const bool include_watch_only = GetLegacyScriptPubKeyMan() && IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); - const isminetype is_mine_filter = include_watch_only ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE; - for (const COutPoint& output : lockedCoins) { - auto it = mapWallet.find(output.hash); - if (it != mapWallet.end()) { - int depth = it->second.GetDepthInMainChain(); - if (depth >= 0 && output.n < it->second.tx->vout.size() && - IsMine(it->second.tx->vout[output.n]) == is_mine_filter - ) { - CTxDestination address; - if (ExtractDestination(FindNonChangeParentOutput(*it->second.tx, output.n).scriptPubKey, address)) { - result[address].emplace_back( - &it->second, output.n, depth, true /* spendable */, true /* solvable */, false /* safe */); - } - } - } - } - - return result; -} - -const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int output) const -{ - AssertLockHeld(cs_wallet); - const CTransaction* ptx = &tx; - int n = output; - while (IsChange(ptx->vout[n]) && ptx->vin.size() > 0) { - const COutPoint& prevout = ptx->vin[0].prevout; - auto it = mapWallet.find(prevout.hash); - if (it == mapWallet.end() || it->second.tx->vout.size() <= prevout.n || - !IsMine(it->second.tx->vout[prevout.n])) { - break; - } - ptx = it->second.tx.get(); - n = prevout.n; - } - return ptx->vout[n]; -} - -bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, - std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params) const -{ - setCoinsRet.clear(); - nValueRet = 0; - - // Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output. - std::vector<OutputGroup> positive_groups = GroupOutputs(coins, coin_selection_params, eligibility_filter, true /* positive_only */); - if (SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change, setCoinsRet, nValueRet)) { - return true; - } - // The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here. - std::vector<OutputGroup> all_groups = GroupOutputs(coins, coin_selection_params, eligibility_filter, false /* positive_only */); - // While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output. - // So we need to include that for KnapsackSolver as well, as we are expecting to create a change output. - return KnapsackSolver(nTargetValue + coin_selection_params.m_change_fee, all_groups, setCoinsRet, nValueRet); -} - -bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params) const -{ - std::vector<COutput> vCoins(vAvailableCoins); - CAmount value_to_select = nTargetValue; - - // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) - if (coin_control.HasSelected() && !coin_control.fAllowOtherInputs) - { - for (const COutput& out : vCoins) - { - if (!out.fSpendable) - continue; - nValueRet += out.tx->tx->vout[out.i].nValue; - setCoinsRet.insert(out.GetInputCoin()); - } - return (nValueRet >= nTargetValue); - } - - // calculate value from preset inputs and store them - std::set<CInputCoin> setPresetCoins; - CAmount nValueFromPresetInputs = 0; - - std::vector<COutPoint> vPresetInputs; - coin_control.ListSelected(vPresetInputs); - for (const COutPoint& outpoint : vPresetInputs) - { - std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); - if (it != mapWallet.end()) - { - const CWalletTx& wtx = it->second; - // Clearly invalid input, fail - if (wtx.tx->vout.size() <= outpoint.n) { - return false; - } - // Just to calculate the marginal byte size - CInputCoin coin(wtx.tx, outpoint.n, wtx.GetSpendSize(outpoint.n, false)); - nValueFromPresetInputs += coin.txout.nValue; - if (coin.m_input_bytes <= 0) { - return false; // Not solvable, can't estimate size for fee - } - coin.effective_value = coin.txout.nValue - coin_selection_params.m_effective_feerate.GetFee(coin.m_input_bytes); - if (coin_selection_params.m_subtract_fee_outputs) { - value_to_select -= coin.txout.nValue; - } else { - value_to_select -= coin.effective_value; - } - setPresetCoins.insert(coin); - } else { - return false; // TODO: Allow non-wallet inputs - } - } - - // remove preset inputs from vCoins so that Coin Selection doesn't pick them. - for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coin_control.HasSelected();) - { - if (setPresetCoins.count(it->GetInputCoin())) - it = vCoins.erase(it); - else - ++it; - } - - unsigned int limit_ancestor_count = 0; - unsigned int limit_descendant_count = 0; - chain().getPackageLimits(limit_ancestor_count, limit_descendant_count); - const size_t max_ancestors = (size_t)std::max<int64_t>(1, limit_ancestor_count); - const size_t max_descendants = (size_t)std::max<int64_t>(1, limit_descendant_count); - const bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS); - - // form groups from remaining coins; note that preset coins will not - // automatically have their associated (same address) coins included - if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) { - // Cases where we have 101+ outputs all pointing to the same destination may result in - // privacy leaks as they will potentially be deterministically sorted. We solve that by - // explicitly shuffling the outputs before processing - Shuffle(vCoins.begin(), vCoins.end(), FastRandomContext()); - } - - // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the - // transaction at a target feerate. If an attempt fails, more attempts may be made using a more - // permissive CoinEligibilityFilter. - const bool res = [&] { - // Pre-selected inputs already cover the target amount. - if (value_to_select <= 0) return true; - - // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six - // confirmations on outputs received from other wallets and only spend confirmed change. - if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true; - if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true; - - // Fall back to using zero confirmation change (but with as few ancestors in the mempool as - // possible) if we cannot fund the transaction otherwise. - if (m_spend_zero_conf_change) { - if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true; - if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), - vCoins, setCoinsRet, nValueRet, coin_selection_params)) { - return true; - } - if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), - vCoins, setCoinsRet, nValueRet, coin_selection_params)) { - return true; - } - // If partial groups are allowed, relax the requirement of spending OutputGroups (groups - // of UTXOs sent to the same address, which are obviously controlled by a single wallet) - // in their entirety. - if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), - vCoins, setCoinsRet, nValueRet, coin_selection_params)) { - return true; - } - // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs - // received from other wallets. - if (coin_control.m_include_unsafe_inputs - && SelectCoinsMinConf(value_to_select, - CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), - vCoins, setCoinsRet, nValueRet, coin_selection_params)) { - return true; - } - // Try with unlimited ancestors/descendants. The transaction will still need to meet - // mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but - // OutputGroups use heuristics that may overestimate ancestor/descendant counts. - if (!fRejectLongChains && SelectCoinsMinConf(value_to_select, - CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */), - vCoins, setCoinsRet, nValueRet, coin_selection_params)) { - return true; - } - } - // Coin Selection failed. - return false; - }(); - - // SelectCoinsMinConf clears setCoinsRet, so add the preset inputs from coin_control to the coinset - util::insert(setCoinsRet, setPresetCoins); - - // add preset inputs to the total value selected - nValueRet += nValueFromPresetInputs; - - return res; -} - bool CWallet::SignTransaction(CMutableTransaction& tx) const { AssertLockHeld(cs_wallet); @@ -2645,118 +1887,6 @@ SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkh return SigningResult::PRIVATE_KEY_NOT_AVAILABLE; } -bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl) -{ - std::vector<CRecipient> vecSend; - - // Turn the txout set into a CRecipient vector. - for (size_t idx = 0; idx < tx.vout.size(); idx++) { - const CTxOut& txOut = tx.vout[idx]; - CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1}; - vecSend.push_back(recipient); - } - - coinControl.fAllowOtherInputs = true; - - for (const CTxIn& txin : tx.vin) { - coinControl.Select(txin.prevout); - } - - // Acquire the locks to prevent races to the new locked unspents between the - // CreateTransaction call and LockCoin calls (when lockUnspents is true). - LOCK(cs_wallet); - - CTransactionRef tx_new; - FeeCalculation fee_calc_out; - if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, fee_calc_out, false)) { - return false; - } - - if (nChangePosInOut != -1) { - tx.vout.insert(tx.vout.begin() + nChangePosInOut, tx_new->vout[nChangePosInOut]); - } - - // Copy output sizes from new transaction; they may have had the fee - // subtracted from them. - for (unsigned int idx = 0; idx < tx.vout.size(); idx++) { - tx.vout[idx].nValue = tx_new->vout[idx].nValue; - } - - // Add new txins while keeping original txin scriptSig/order. - for (const CTxIn& txin : tx_new->vin) { - if (!coinControl.IsSelected(txin.prevout)) { - tx.vin.push_back(txin); - - } - if (lockUnspents) { - LockCoin(txin.prevout); - } - - } - - return true; -} - -static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256& block_hash) -{ - if (chain.isInitialBlockDownload()) { - return false; - } - constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds - int64_t block_time; - CHECK_NONFATAL(chain.findBlock(block_hash, FoundBlock().time(block_time))); - if (block_time < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) { - return false; - } - return true; -} - -/** - * Return a height-based locktime for new transactions (uses the height of the - * current chain tip unless we are not synced with the current chain - */ -static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uint256& block_hash, int block_height) -{ - uint32_t locktime; - // Discourage fee sniping. - // - // For a large miner the value of the transactions in the best block and - // the mempool can exceed the cost of deliberately attempting to mine two - // blocks to orphan the current best block. By setting nLockTime such that - // only the next block can include the transaction, we discourage this - // practice as the height restricted and limited blocksize gives miners - // considering fee sniping fewer options for pulling off this attack. - // - // A simple way to think about this is from the wallet's point of view we - // always want the blockchain to move forward. By setting nLockTime this - // way we're basically making the statement that we only want this - // transaction to appear in the next block; we don't want to potentially - // encourage reorgs by allowing transactions to appear at lower heights - // than the next block in forks of the best chain. - // - // Of course, the subsidy is high enough, and transaction volume low - // enough, that fee sniping isn't a problem yet, but by implementing a fix - // now we ensure code won't be written that makes assumptions about - // nLockTime that preclude a fix later. - if (IsCurrentForAntiFeeSniping(chain, block_hash)) { - locktime = block_height; - - // Secondly occasionally randomly pick a nLockTime even further back, so - // that transactions that are delayed after signing for whatever reason, - // e.g. high-latency mix networks and some CoinJoin implementations, have - // better privacy. - if (GetRandInt(10) == 0) - locktime = std::max(0, (int)locktime - GetRandInt(100)); - } else { - // If our chain is lagging behind, we can't discourage fee sniping nor help - // the privacy of high-latency transactions. To avoid leaking a potentially - // unique "nLockTime fingerprint", set nLockTime to a constant. - locktime = 0; - } - assert(locktime < LOCKTIME_THRESHOLD); - return locktime; -} - OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const { // If -changetype is specified, always use that change type. @@ -2785,363 +1915,6 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang return m_default_address_type; } -bool CWallet::CreateTransactionInternal( - const std::vector<CRecipient>& vecSend, - CTransactionRef& tx, - CAmount& nFeeRet, - int& nChangePosInOut, - bilingual_str& error, - const CCoinControl& coin_control, - FeeCalculation& fee_calc_out, - bool sign) -{ - CAmount nValue = 0; - const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend); - ReserveDestination reservedest(this, change_type); - unsigned int nSubtractFeeFromAmount = 0; - for (const auto& recipient : vecSend) - { - if (nValue < 0 || recipient.nAmount < 0) - { - error = _("Transaction amounts must not be negative"); - return false; - } - nValue += recipient.nAmount; - - if (recipient.fSubtractFeeFromAmount) - nSubtractFeeFromAmount++; - } - if (vecSend.empty()) - { - error = _("Transaction must have at least one recipient"); - return false; - } - - CMutableTransaction txNew; - FeeCalculation feeCalc; - TxSize tx_sizes; - int nBytes; - { - std::set<CInputCoin> setCoins; - LOCK(cs_wallet); - txNew.nLockTime = GetLocktimeForNewTransaction(chain(), GetLastBlockHash(), GetLastBlockHeight()); - { - std::vector<COutput> vAvailableCoins; - AvailableCoins(vAvailableCoins, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0); - CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy - coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends; - - // Create change script that will be used if we need change - // TODO: pass in scriptChange instead of reservedest so - // change transaction isn't always pay-to-bitcoin-address - CScript scriptChange; - - // coin control: send change to custom address - if (!std::get_if<CNoDestination>(&coin_control.destChange)) { - scriptChange = GetScriptForDestination(coin_control.destChange); - } else { // no coin control: send change to newly generated address - // Note: We use a new key here to keep it from being obvious which side is the change. - // The drawback is that by not reusing a previous key, the change may be lost if a - // backup is restored, if the backup doesn't have the new private key for the change. - // If we reused the old key, it would be possible to add code to look for and - // rediscover unknown transactions that were written with keys of ours to recover - // post-backup change. - - // Reserve a new key pair from key pool. If it fails, provide a dummy - // destination in case we don't need change. - CTxDestination dest; - if (!reservedest.GetReservedDestination(dest, true)) { - error = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first."); - } - scriptChange = GetScriptForDestination(dest); - // A valid destination implies a change script (and - // vice-versa). An empty change script will abort later, if the - // change keypool ran out, but change is required. - CHECK_NONFATAL(IsValidDestination(dest) != scriptChange.empty()); - } - CTxOut change_prototype_txout(0, scriptChange); - coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout); - - // Get size of spending the change output - int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, this); - // If the wallet doesn't know how to sign change output, assume p2sh-p2wpkh - // as lower-bound to allow BnB to do it's thing - if (change_spend_size == -1) { - coin_selection_params.change_spend_size = DUMMY_NESTED_P2WPKH_INPUT_SIZE; - } else { - coin_selection_params.change_spend_size = (size_t)change_spend_size; - } - - // Set discard feerate - coin_selection_params.m_discard_feerate = GetDiscardRate(*this); - - // Get the fee rate to use effective values in coin selection - coin_selection_params.m_effective_feerate = GetMinimumFeeRate(*this, coin_control, &feeCalc); - // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly - // provided one - if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) { - error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB)); - return false; - } - if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) { - // eventually allow a fallback fee - error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee."); - return false; - } - - // Get long term estimate - CCoinControl cc_temp; - cc_temp.m_confirm_target = chain().estimateMaxBlocks(); - coin_selection_params.m_long_term_feerate = GetMinimumFeeRate(*this, cc_temp, nullptr); - - // Calculate the cost of change - // Cost of change is the cost of creating the change output + cost of spending the change output in the future. - // For creating the change output now, we use the effective feerate. - // For spending the change output in the future, we use the discard feerate for now. - // So cost of change = (change output size * effective feerate) + (size of spending change output * discard feerate) - coin_selection_params.m_change_fee = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size); - coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_change_fee; - - coin_selection_params.m_subtract_fee_outputs = nSubtractFeeFromAmount != 0; // If we are doing subtract fee from recipient, don't use effective values - - // vouts to the payees - if (!coin_selection_params.m_subtract_fee_outputs) { - coin_selection_params.tx_noinputs_size = 11; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 output count, 1 witness overhead (dummy, flag, stack size) - } - for (const auto& recipient : vecSend) - { - CTxOut txout(recipient.nAmount, recipient.scriptPubKey); - - // Include the fee cost for outputs. - if (!coin_selection_params.m_subtract_fee_outputs) { - coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION); - } - - if (IsDust(txout, chain().relayDustFee())) - { - error = _("Transaction amount too small"); - return false; - } - txNew.vout.push_back(txout); - } - - // Include the fees for things that aren't inputs, excluding the change output - const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size); - CAmount nValueToSelect = nValue + not_input_fees; - - // Choose coins to use - CAmount inputs_sum = 0; - setCoins.clear(); - if (!SelectCoins(vAvailableCoins, /* nTargetValue */ nValueToSelect, setCoins, inputs_sum, coin_control, coin_selection_params)) - { - error = _("Insufficient funds"); - return false; - } - - // Always make a change output - // We will reduce the fee from this change output later, and remove the output if it is too small. - const CAmount change_and_fee = inputs_sum - nValue; - assert(change_and_fee >= 0); - CTxOut newTxOut(change_and_fee, scriptChange); - - if (nChangePosInOut == -1) - { - // Insert change txn at random position: - nChangePosInOut = GetRandInt(txNew.vout.size()+1); - } - else if ((unsigned int)nChangePosInOut > txNew.vout.size()) - { - error = _("Change index out of range"); - return false; - } - - assert(nChangePosInOut != -1); - auto change_position = txNew.vout.insert(txNew.vout.begin() + nChangePosInOut, newTxOut); - - // Dummy fill vin for maximum size estimation - // - for (const auto& coin : setCoins) { - txNew.vin.push_back(CTxIn(coin.outpoint,CScript())); - } - - // Calculate the transaction fee - tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly); - nBytes = tx_sizes.vsize; - if (nBytes < 0) { - error = _("Signing transaction failed"); - return false; - } - nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes); - - // Subtract fee from the change output if not subtrating it from recipient outputs - CAmount fee_needed = nFeeRet; - if (nSubtractFeeFromAmount == 0) { - change_position->nValue -= fee_needed; - } - - // We want to drop the change to fees if: - // 1. The change output would be dust - // 2. The change is within the (almost) exact match window, i.e. it is less than or equal to the cost of the change output (cost_of_change) - CAmount change_amount = change_position->nValue; - if (IsDust(*change_position, coin_selection_params.m_discard_feerate) || change_amount <= coin_selection_params.m_cost_of_change) - { - nChangePosInOut = -1; - change_amount = 0; - txNew.vout.erase(change_position); - - // Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those - tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly); - nBytes = tx_sizes.vsize; - fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes); - } - - // Update nFeeRet in case fee_needed changed due to dropping the change output - if (fee_needed <= change_and_fee - change_amount) { - nFeeRet = change_and_fee - change_amount; - } - - // Reduce output values for subtractFeeFromAmount - if (nSubtractFeeFromAmount != 0) { - CAmount to_reduce = fee_needed + change_amount - change_and_fee; - int i = 0; - bool fFirst = true; - for (const auto& recipient : vecSend) - { - if (i == nChangePosInOut) { - ++i; - } - CTxOut& txout = txNew.vout[i]; - - if (recipient.fSubtractFeeFromAmount) - { - txout.nValue -= to_reduce / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient - - if (fFirst) // first receiver pays the remainder not divisible by output count - { - fFirst = false; - txout.nValue -= to_reduce % nSubtractFeeFromAmount; - } - - // Error if this output is reduced to be below dust - if (IsDust(txout, chain().relayDustFee())) { - if (txout.nValue < 0) { - error = _("The transaction amount is too small to pay the fee"); - } else { - error = _("The transaction amount is too small to send after the fee has been deducted"); - } - return false; - } - } - ++i; - } - nFeeRet = fee_needed; - } - - // Give up if change keypool ran out and change is required - if (scriptChange.empty() && nChangePosInOut != -1) { - return false; - } - } - - // Shuffle selected coins and fill in final vin - txNew.vin.clear(); - std::vector<CInputCoin> selected_coins(setCoins.begin(), setCoins.end()); - Shuffle(selected_coins.begin(), selected_coins.end(), FastRandomContext()); - - // Note how the sequence number is set to non-maxint so that - // the nLockTime set above actually works. - // - // BIP125 defines opt-in RBF as any nSequence < maxint-1, so - // we use the highest possible value in that range (maxint-2) - // to avoid conflicting with other possible uses of nSequence, - // and in the spirit of "smallest possible change from prior - // behavior." - const uint32_t nSequence = coin_control.m_signal_bip125_rbf.value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); - for (const auto& coin : selected_coins) { - txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence)); - } - - if (sign && !SignTransaction(txNew)) { - error = _("Signing transaction failed"); - return false; - } - - // Return the constructed transaction data. - tx = MakeTransactionRef(std::move(txNew)); - - // Limit size - if ((sign && GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) || - (!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT)) - { - error = _("Transaction too large"); - return false; - } - } - - if (nFeeRet > m_default_max_tx_fee) { - error = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED); - return false; - } - - if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { - // Lastly, ensure this tx will pass the mempool's chain limits - if (!chain().checkChainLimits(tx)) { - error = _("Transaction has too long of a mempool chain"); - return false; - } - } - - // Before we return success, we assume any change key will be used to prevent - // accidental re-use. - reservedest.KeepDestination(); - fee_calc_out = feeCalc; - - WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", - nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, - feeCalc.est.pass.start, feeCalc.est.pass.end, - (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0, - feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool, - feeCalc.est.fail.start, feeCalc.est.fail.end, - (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0, - feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool); - return true; -} - -bool CWallet::CreateTransaction( - const std::vector<CRecipient>& vecSend, - CTransactionRef& tx, - CAmount& nFeeRet, - int& nChangePosInOut, - bilingual_str& error, - const CCoinControl& coin_control, - FeeCalculation& fee_calc_out, - bool sign) -{ - int nChangePosIn = nChangePosInOut; - Assert(!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr) - bool res = CreateTransactionInternal(vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, fee_calc_out, sign); - // try with avoidpartialspends unless it's enabled already - if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) { - CCoinControl tmp_cc = coin_control; - tmp_cc.m_avoid_partial_spends = true; - CAmount nFeeRet2; - CTransactionRef tx2; - int nChangePosInOut2 = nChangePosIn; - bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results - if (CreateTransactionInternal(vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign)) { - // if fee of this alternative one is within the range of the max fee, we use this one - const bool use_aps = nFeeRet2 <= nFeeRet + m_max_aps_fee; - WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n", nFeeRet, nFeeRet2, use_aps ? "grouped" : "non-grouped"); - if (use_aps) { - tx = tx2; - nFeeRet = nFeeRet2; - nChangePosInOut = nChangePosInOut2; - } - } - } - return res; -} - void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm) { LOCK(cs_wallet); @@ -3385,137 +2158,6 @@ void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations } } -std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() const -{ - std::map<CTxDestination, CAmount> balances; - - { - LOCK(cs_wallet); - std::set<uint256> trusted_parents; - for (const auto& walletEntry : mapWallet) - { - const CWalletTx& wtx = walletEntry.second; - - if (!IsTrusted(wtx, trusted_parents)) - continue; - - if (wtx.IsImmatureCoinBase()) - continue; - - int nDepth = wtx.GetDepthInMainChain(); - if (nDepth < (wtx.IsFromMe(ISMINE_ALL) ? 0 : 1)) - continue; - - for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) - { - CTxDestination addr; - if (!IsMine(wtx.tx->vout[i])) - continue; - if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr)) - continue; - - CAmount n = IsSpent(walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue; - balances[addr] += n; - } - } - } - - return balances; -} - -std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() const -{ - AssertLockHeld(cs_wallet); - std::set< std::set<CTxDestination> > groupings; - std::set<CTxDestination> grouping; - - for (const auto& walletEntry : mapWallet) - { - const CWalletTx& wtx = walletEntry.second; - - if (wtx.tx->vin.size() > 0) - { - bool any_mine = false; - // group all input addresses with each other - for (const CTxIn& txin : wtx.tx->vin) - { - CTxDestination address; - if(!IsMine(txin)) /* If this input isn't mine, ignore it */ - continue; - if(!ExtractDestination(mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address)) - continue; - grouping.insert(address); - any_mine = true; - } - - // group change with input addresses - if (any_mine) - { - for (const CTxOut& txout : wtx.tx->vout) - if (IsChange(txout)) - { - CTxDestination txoutAddr; - if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) - continue; - grouping.insert(txoutAddr); - } - } - if (grouping.size() > 0) - { - groupings.insert(grouping); - grouping.clear(); - } - } - - // group lone addrs by themselves - for (const auto& txout : wtx.tx->vout) - if (IsMine(txout)) - { - CTxDestination address; - if(!ExtractDestination(txout.scriptPubKey, address)) - continue; - grouping.insert(address); - groupings.insert(grouping); - grouping.clear(); - } - } - - std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses - std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it - for (std::set<CTxDestination> _grouping : groupings) - { - // make a set of all the groups hit by this new group - std::set< std::set<CTxDestination>* > hits; - std::map< CTxDestination, std::set<CTxDestination>* >::iterator it; - for (const CTxDestination& address : _grouping) - if ((it = setmap.find(address)) != setmap.end()) - hits.insert((*it).second); - - // merge all hit groups into a new single group and delete old groups - std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping); - for (std::set<CTxDestination>* hit : hits) - { - merged->insert(hit->begin(), hit->end()); - uniqueGroupings.erase(hit); - delete hit; - } - uniqueGroupings.insert(merged); - - // update setmap - for (const CTxDestination& element : *merged) - setmap[element] = merged; - } - - std::set< std::set<CTxDestination> > ret; - for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) - { - ret.insert(*uniqueGrouping); - delete uniqueGrouping; - } - - return ret; -} - std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) const { LOCK(cs_wallet); @@ -3744,45 +2386,45 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const return nTimeSmart; } -bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key, const std::string &value) +bool CWallet::SetAddressUsed(WalletBatch& batch, const CTxDestination& dest, bool used) { + const std::string key{"used"}; if (std::get_if<CNoDestination>(&dest)) return false; + if (!used) { + if (auto* data = util::FindKey(m_address_book, dest)) data->destdata.erase(key); + return batch.EraseDestData(EncodeDestination(dest), key); + } + + const std::string value{"1"}; m_address_book[dest].destdata.insert(std::make_pair(key, value)); return batch.WriteDestData(EncodeDestination(dest), key, value); } -bool CWallet::EraseDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key) -{ - if (!m_address_book[dest].destdata.erase(key)) - return false; - return batch.EraseDestData(EncodeDestination(dest), key); -} - void CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) { m_address_book[dest].destdata.insert(std::make_pair(key, value)); } -bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const +bool CWallet::IsAddressUsed(const CTxDestination& dest) const { + const std::string key{"used"}; std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dest); if(i != m_address_book.end()) { CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); if(j != i->second.destdata.end()) { - if(value) - *value = j->second; return true; } } return false; } -std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const +std::vector<std::string> CWallet::GetAddressReceiveRequests() const { + const std::string prefix{"rr"}; std::vector<std::string> values; for (const auto& address : m_address_book) { for (const auto& data : address.second.destdata) { @@ -3794,6 +2436,20 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const return values; } +bool CWallet::SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value) +{ + const std::string key{"rr" + id}; // "rr" prefix = "receive request" in destdata + CAddressBookData& data = m_address_book.at(dest); + if (value.empty()) { + if (!batch.EraseDestData(EncodeDestination(dest), key)) return false; + data.destdata.erase(key); + } else { + if (!batch.WriteDestData(EncodeDestination(dest), key, value)) return false; + data.destdata[key] = value; + } + return true; +} + std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string) { // Do some checking on wallet path. It should be either a: @@ -4231,92 +2887,6 @@ bool CWalletTx::IsImmatureCoinBase() const return GetBlocksToMaturity() > 0; } -std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only) const -{ - std::vector<OutputGroup> groups_out; - - if (!coin_sel_params.m_avoid_partial_spends) { - // Allowing partial spends means no grouping. Each COutput gets its own OutputGroup. - for (const COutput& output : outputs) { - // Skip outputs we cannot spend - if (!output.fSpendable) continue; - - size_t ancestors, descendants; - chain().getTransactionAncestry(output.tx->GetHash(), ancestors, descendants); - CInputCoin input_coin = output.GetInputCoin(); - - // Make an OutputGroup containing just this output - OutputGroup group{coin_sel_params}; - group.Insert(input_coin, output.nDepth, output.tx->IsFromMe(ISMINE_ALL), ancestors, descendants, positive_only); - - // Check the OutputGroup's eligibility. Only add the eligible ones. - if (positive_only && group.GetSelectionAmount() <= 0) continue; - if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter)) groups_out.push_back(group); - } - return groups_out; - } - - // We want to combine COutputs that have the same scriptPubKey into single OutputGroups - // except when there are more than OUTPUT_GROUP_MAX_ENTRIES COutputs grouped in an OutputGroup. - // To do this, we maintain a map where the key is the scriptPubKey and the value is a vector of OutputGroups. - // For each COutput, we check if the scriptPubKey is in the map, and if it is, the COutput's CInputCoin is added - // to the last OutputGroup in the vector for the scriptPubKey. When the last OutputGroup has - // OUTPUT_GROUP_MAX_ENTRIES CInputCoins, a new OutputGroup is added to the end of the vector. - std::map<CScript, std::vector<OutputGroup>> spk_to_groups_map; - for (const auto& output : outputs) { - // Skip outputs we cannot spend - if (!output.fSpendable) continue; - - size_t ancestors, descendants; - chain().getTransactionAncestry(output.tx->GetHash(), ancestors, descendants); - CInputCoin input_coin = output.GetInputCoin(); - CScript spk = input_coin.txout.scriptPubKey; - - std::vector<OutputGroup>& groups = spk_to_groups_map[spk]; - - if (groups.size() == 0) { - // No OutputGroups for this scriptPubKey yet, add one - groups.emplace_back(coin_sel_params); - } - - // Get the last OutputGroup in the vector so that we can add the CInputCoin to it - // A pointer is used here so that group can be reassigned later if it is full. - OutputGroup* group = &groups.back(); - - // Check if this OutputGroup is full. We limit to OUTPUT_GROUP_MAX_ENTRIES when using -avoidpartialspends - // to avoid surprising users with very high fees. - if (group->m_outputs.size() >= OUTPUT_GROUP_MAX_ENTRIES) { - // The last output group is full, add a new group to the vector and use that group for the insertion - groups.emplace_back(coin_sel_params); - group = &groups.back(); - } - - // Add the input_coin to group - group->Insert(input_coin, output.nDepth, output.tx->IsFromMe(ISMINE_ALL), ancestors, descendants, positive_only); - } - - // Now we go through the entire map and pull out the OutputGroups - for (const auto& spk_and_groups_pair: spk_to_groups_map) { - const std::vector<OutputGroup>& groups_per_spk= spk_and_groups_pair.second; - - // Go through the vector backwards. This allows for the first item we deal with being the partial group. - for (auto group_it = groups_per_spk.rbegin(); group_it != groups_per_spk.rend(); group_it++) { - const OutputGroup& group = *group_it; - - // Don't include partial groups if there are full groups too and we don't want partial groups - if (group_it == groups_per_spk.rbegin() && groups_per_spk.size() > 1 && !filter.m_include_partial_groups) { - continue; - } - - // Check the OutputGroup's eligibility. Only add the eligible ones. - if (positive_only && group.GetSelectionAmount() <= 0) continue; - if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter)) groups_out.push_back(group); - } - } - - return groups_out; -} - bool CWallet::IsCrypted() const { return HasEncryptionKeys(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9a572bc610..788a901f95 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -21,8 +21,11 @@ #include <validationinterface.h> #include <wallet/coinselection.h> #include <wallet/crypter.h> -#include <wallet/scriptpubkeyman.h> #include <external_signer.h> +#include <wallet/receive.h> +#include <wallet/scriptpubkeyman.h> +#include <wallet/spend.h> +#include <wallet/transaction.h> #include <wallet/walletdb.h> #include <wallet/walletutil.h> @@ -215,403 +218,6 @@ struct CRecipient bool fSubtractFeeFromAmount; }; -typedef std::map<std::string, std::string> mapValue_t; - - -static inline void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue) -{ - if (!mapValue.count("n")) - { - nOrderPos = -1; // TODO: calculate elsewhere - return; - } - nOrderPos = atoi64(mapValue["n"]); -} - - -static inline void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue) -{ - if (nOrderPos == -1) - return; - mapValue["n"] = ToString(nOrderPos); -} - -struct COutputEntry -{ - CTxDestination destination; - CAmount amount; - int vout; -}; - -/** Legacy class used for deserializing vtxPrev for backwards compatibility. - * vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3, - * but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs. - * These need to get deserialized for field alignment when deserializing - * a CWalletTx, but the deserialized values are discarded.**/ -class CMerkleTx -{ -public: - template<typename Stream> - void Unserialize(Stream& s) - { - CTransactionRef tx; - uint256 hashBlock; - std::vector<uint256> vMerkleBranch; - int nIndex; - - s >> tx >> hashBlock >> vMerkleBranch >> nIndex; - } -}; - -//Get the marginal bytes of spending the specified output -int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, bool use_max_sig = false); - -/** - * A transaction with a bunch of additional info that only the owner cares about. - * It includes any unrecorded transactions needed to link it back to the block chain. - */ -class CWalletTx -{ -private: - const CWallet* const pwallet; - - /** Constant used in hashBlock to indicate tx has been abandoned, only used at - * serialization/deserialization to avoid ambiguity with conflicted. - */ - static constexpr const uint256& ABANDON_HASH = uint256::ONE; - -public: - /** - * Key/value map with information about the transaction. - * - * The following keys can be read and written through the map and are - * serialized in the wallet database: - * - * "comment", "to" - comment strings provided to sendtoaddress, - * and sendmany wallet RPCs - * "replaces_txid" - txid (as HexStr) of transaction replaced by - * bumpfee on transaction created by bumpfee - * "replaced_by_txid" - txid (as HexStr) of transaction created by - * bumpfee on transaction replaced by bumpfee - * "from", "message" - obsolete fields that could be set in UI prior to - * 2011 (removed in commit 4d9b223) - * - * The following keys are serialized in the wallet database, but shouldn't - * be read or written through the map (they will be temporarily added and - * removed from the map during serialization): - * - * "fromaccount" - serialized strFromAccount value - * "n" - serialized nOrderPos value - * "timesmart" - serialized nTimeSmart value - * "spent" - serialized vfSpent value that existed prior to - * 2014 (removed in commit 93a18a3) - */ - mapValue_t mapValue; - std::vector<std::pair<std::string, std::string> > vOrderForm; - unsigned int fTimeReceivedIsTxTime; - unsigned int nTimeReceived; //!< time received by this node - /** - * Stable timestamp that never changes, and reflects the order a transaction - * was added to the wallet. Timestamp is based on the block time for a - * transaction added as part of a block, or else the time when the - * transaction was received if it wasn't part of a block, with the timestamp - * adjusted in both cases so timestamp order matches the order transactions - * were added to the wallet. More details can be found in - * CWallet::ComputeTimeSmart(). - */ - unsigned int nTimeSmart; - /** - * From me flag is set to 1 for transactions that were created by the wallet - * on this bitcoin node, and set to 0 for transactions that were created - * externally and came in through the network or sendrawtransaction RPC. - */ - bool fFromMe; - int64_t nOrderPos; //!< position in ordered transaction list - std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered; - - // memory only - enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS }; - CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const; - mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]; - /** - * This flag is true if all m_amounts caches are empty. This is particularly - * useful in places where MarkDirty is conditionally called and the - * condition can be expensive and thus can be skipped if the flag is true. - * See MarkDestinationsDirty. - */ - mutable bool m_is_cache_empty{true}; - mutable bool fChangeCached; - mutable bool fInMempool; - mutable CAmount nChangeCached; - - CWalletTx(const CWallet* wallet, CTransactionRef arg) - : pwallet(wallet), - tx(std::move(arg)) - { - Init(); - } - - void Init() - { - mapValue.clear(); - vOrderForm.clear(); - fTimeReceivedIsTxTime = false; - nTimeReceived = 0; - nTimeSmart = 0; - fFromMe = false; - fChangeCached = false; - fInMempool = false; - nChangeCached = 0; - nOrderPos = -1; - m_confirm = Confirmation{}; - } - - CTransactionRef tx; - - /** New transactions start as UNCONFIRMED. At BlockConnected, - * they will transition to CONFIRMED. In case of reorg, at BlockDisconnected, - * they roll back to UNCONFIRMED. If we detect a conflicting transaction at - * block connection, we update conflicted tx and its dependencies as CONFLICTED. - * If tx isn't confirmed and outside of mempool, the user may switch it to ABANDONED - * by using the abandontransaction call. This last status may be override by a CONFLICTED - * or CONFIRMED transition. - */ - enum Status { - UNCONFIRMED, - CONFIRMED, - CONFLICTED, - ABANDONED - }; - - /** Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} - * at which tx has been confirmed. All three are set to 0 if tx is unconfirmed or abandoned. - * Meaning of these fields changes with CONFLICTED state where they instead point to block hash - * and block height of the deepest conflicting tx. - */ - struct Confirmation { - Status status; - int block_height; - uint256 hashBlock; - int nIndex; - Confirmation(Status s = UNCONFIRMED, int b = 0, uint256 h = uint256(), int i = 0) : status(s), block_height(b), hashBlock(h), nIndex(i) {} - }; - - Confirmation m_confirm; - - template<typename Stream> - void Serialize(Stream& s) const - { - mapValue_t mapValueCopy = mapValue; - - mapValueCopy["fromaccount"] = ""; - WriteOrderPos(nOrderPos, mapValueCopy); - if (nTimeSmart) { - mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); - } - - std::vector<char> dummy_vector1; //!< Used to be vMerkleBranch - std::vector<char> dummy_vector2; //!< Used to be vtxPrev - bool dummy_bool = false; //!< Used to be fSpent - uint256 serializedHash = isAbandoned() ? ABANDON_HASH : m_confirm.hashBlock; - int serializedIndex = isAbandoned() || isConflicted() ? -1 : m_confirm.nIndex; - s << tx << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool; - } - - template<typename Stream> - void Unserialize(Stream& s) - { - Init(); - - std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch - std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev - bool dummy_bool; //! Used to be fSpent - int serializedIndex; - s >> tx >> m_confirm.hashBlock >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_bool; - - /* At serialization/deserialization, an nIndex == -1 means that hashBlock refers to - * the earliest block in the chain we know this or any in-wallet ancestor conflicts - * with. If nIndex == -1 and hashBlock is ABANDON_HASH, it means transaction is abandoned. - * In same context, an nIndex >= 0 refers to a confirmed transaction (if hashBlock set) or - * unconfirmed one. Older clients interpret nIndex == -1 as unconfirmed for backward - * compatibility (pre-commit 9ac63d6). - */ - if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) { - setAbandoned(); - } else if (serializedIndex == -1) { - setConflicted(); - } else if (!m_confirm.hashBlock.IsNull()) { - m_confirm.nIndex = serializedIndex; - setConfirmed(); - } - - ReadOrderPos(nOrderPos, mapValue); - nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0; - - mapValue.erase("fromaccount"); - mapValue.erase("spent"); - mapValue.erase("n"); - mapValue.erase("timesmart"); - } - - void SetTx(CTransactionRef arg) - { - tx = std::move(arg); - } - - //! make sure balances are recalculated - void MarkDirty() - { - m_amounts[DEBIT].Reset(); - m_amounts[CREDIT].Reset(); - m_amounts[IMMATURE_CREDIT].Reset(); - m_amounts[AVAILABLE_CREDIT].Reset(); - fChangeCached = false; - m_is_cache_empty = true; - } - - //! filter decides which addresses will count towards the debit - CAmount GetDebit(const isminefilter& filter) const; - CAmount GetCredit(const isminefilter& filter) const; - CAmount GetImmatureCredit(bool fUseCache = true) const; - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The - // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid - // having to resolve the issue of member access into incomplete type CWallet. - CAmount GetAvailableCredit(bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS; - CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const; - CAmount GetChange() const; - - /** Get the marginal bytes if spending the specified output from this transaction */ - int GetSpendSize(unsigned int out, bool use_max_sig = false) const - { - return CalculateMaximumSignedInputSize(tx->vout[out], pwallet, use_max_sig); - } - - void GetAmounts(std::list<COutputEntry>& listReceived, - std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const; - - bool IsFromMe(const isminefilter& filter) const - { - return (GetDebit(filter) > 0); - } - - /** True if only scriptSigs are different */ - bool IsEquivalentTo(const CWalletTx& tx) const; - - bool InMempool() const; - bool IsTrusted() const; - - int64_t GetTxTime() const; - - /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ - bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay); - - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation - // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to - // resolve the issue of member access into incomplete type CWallet. Note - // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" - // in place. - std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; - - /** - * Return depth of transaction in blockchain: - * <0 : conflicts with a transaction this deep in the blockchain - * 0 : in memory pool, waiting to be included in a block - * >=1 : this many blocks deep in the main chain - */ - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation - // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to - // resolve the issue of member access into incomplete type CWallet. Note - // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" - // in place. - int GetDepthInMainChain() const NO_THREAD_SAFETY_ANALYSIS; - bool IsInMainChain() const { return GetDepthInMainChain() > 0; } - - /** - * @return number of blocks to maturity for this transaction: - * 0 : is not a coinbase transaction, or is a mature coinbase transaction - * >0 : is a coinbase transaction which matures in this many blocks - */ - int GetBlocksToMaturity() const; - bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; } - void setAbandoned() - { - m_confirm.status = CWalletTx::ABANDONED; - m_confirm.hashBlock = uint256(); - m_confirm.block_height = 0; - m_confirm.nIndex = 0; - } - bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; } - void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; } - bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; } - void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; } - bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; } - void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; } - const uint256& GetHash() const { return tx->GetHash(); } - bool IsCoinBase() const { return tx->IsCoinBase(); } - bool IsImmatureCoinBase() const; - - // Disable copying of CWalletTx objects to prevent bugs where instances get - // copied in and out of the mapWallet map, and fields are updated in the - // wrong copy. - CWalletTx(CWalletTx const &) = delete; - void operator=(CWalletTx const &x) = delete; -}; - -class COutput -{ -public: - const CWalletTx *tx; - - /** Index in tx->vout. */ - int i; - - /** - * Depth in block chain. - * If > 0: the tx is on chain and has this many confirmations. - * If = 0: the tx is waiting confirmation. - * If < 0: a conflicting tx is on chain and has this many confirmations. */ - int nDepth; - - /** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */ - int nInputBytes; - - /** Whether we have the private keys to spend this output */ - bool fSpendable; - - /** Whether we know how to spend this output, ignoring the lack of keys */ - bool fSolvable; - - /** Whether to use the maximum sized, 72 byte signature when calculating the size of the input spend. This should only be set when watch-only outputs are allowed */ - bool use_max_sig; - - /** - * Whether this output is considered safe to spend. Unconfirmed transactions - * from outside keys and unconfirmed replacement transactions are considered - * unsafe and will not be used to fund new spending transactions. - */ - bool fSafe; - - COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn, bool use_max_sig_in = false) - { - tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1; use_max_sig = use_max_sig_in; - // If known and signable by the given wallet, compute nInputBytes - // Failure will keep this value -1 - if (fSpendable && tx) { - nInputBytes = tx->GetSpendSize(i, use_max_sig); - } - } - - std::string ToString() const; - - inline CInputCoin GetInputCoin() const - { - return CInputCoin(tx->tx, i, nInputBytes); - } -}; - class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime /** * A CWallet maintains a set of transactions and balances, and provides the ability to create new transactions. @@ -621,7 +227,6 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati private: CKeyingMaterial vMasterKey GUARDED_BY(cs_wallet); - bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); std::atomic<bool> fAbortRescan{false}; @@ -874,19 +479,8 @@ public: bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; return true; } - /** - * Adds a destination data tuple to the store, and saves it to disk - * When adding new fields, take care to consider how DelAddressBook should handle it! - */ - bool AddDestData(WalletBatch& batch, const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! Erases a destination data tuple in the store and on disk - bool EraseDestData(WalletBatch& batch, const CTxDestination& dest, const std::string& key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Adds a destination data tuple to the store, without saving it to disk void LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! Look up a destination data tuple in the store, return true if found false otherwise - bool GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! Get all destination values matching a prefix. - std::vector<std::string> GetDestValues(const std::string& prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock(). int64_t nRelockTime GUARDED_BY(cs_wallet){0}; @@ -1100,6 +694,12 @@ public: bool DelAddressBook(const CTxDestination& address); + bool IsAddressUsed(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool SetAddressUsed(WalletBatch& batch, const CTxDestination& dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + std::vector<std::string> GetAddressReceiveRequests() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! signify that a particular wallet feature is now used. diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 3d9248009f..c06b319b0b 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -155,7 +155,7 @@ bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMet if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) { return false; } - return WriteIC(std::make_pair(DBKeys::WATCHS, dest), '1'); + return WriteIC(std::make_pair(DBKeys::WATCHS, dest), uint8_t{'1'}); } bool WalletBatch::EraseWatchOnly(const CScript &dest) @@ -308,8 +308,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { if (!ssValue.empty()) { - char fTmp; - char fUnused; + uint8_t fTmp; + uint8_t fUnused; std::string unused_string; ssValue >> fTmp >> fUnused >> unused_string; strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s", @@ -336,7 +336,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, wss.nWatchKeys++; CScript script; ssKey >> script; - char fYes; + uint8_t fYes; ssValue >> fYes; if (fYes == '1') { pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script); diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 1a148f04f4..a4480307a7 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -31,6 +31,7 @@ Start three nodes: """ from test_framework.blocktools import ( + COINBASE_MATURITY, create_block, create_coinbase, ) @@ -161,8 +162,8 @@ class AssumeValidTest(BitcoinTestFramework): # Send blocks to node0. Block 102 will be rejected. self.send_blocks_until_disconnected(p2p0) - self.wait_until(lambda: self.nodes[0].getblockcount() >= 101) - assert_equal(self.nodes[0].getblockcount(), 101) + self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1) + assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1) # Send all blocks to node1. All blocks will be accepted. for i in range(2202): @@ -173,8 +174,8 @@ class AssumeValidTest(BitcoinTestFramework): # Send blocks to node2. Block 102 will be rejected. self.send_blocks_until_disconnected(p2p2) - self.wait_until(lambda: self.nodes[2].getblockcount() >= 101) - assert_equal(self.nodes[2].getblockcount(), 101) + self.wait_until(lambda: self.nodes[2].getblockcount() >= COINBASE_MATURITY + 1) + assert_equal(self.nodes[2].getblockcount(), COINBASE_MATURITY + 1) if __name__ == '__main__': diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py index e6a53b52db..c712f7141c 100755 --- a/test/functional/feature_backwards_compatibility.py +++ b/test/functional/feature_backwards_compatibility.py @@ -22,6 +22,7 @@ needs an older patch version. import os import shutil +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.descriptors import descsum_create @@ -64,13 +65,13 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): self.import_deterministic_coinbase_privkeys() def run_test(self): - self.nodes[0].generatetoaddress(101, self.nodes[0].getnewaddress()) + self.nodes[0].generatetoaddress(COINBASE_MATURITY + 1, self.nodes[0].getnewaddress()) self.sync_blocks() # Sanity check the test framework: res = self.nodes[self.num_nodes - 1].getblockchaininfo() - assert_equal(res['blocks'], 101) + assert_equal(res['blocks'], COINBASE_MATURITY + 1) node_master = self.nodes[self.num_nodes - 5] node_v19 = self.nodes[self.num_nodes - 4] diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index d25aaa070d..10d2072dba 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -37,7 +37,7 @@ CLTV_HEIGHT = 1351 # Helper function to modify a transaction by # 1) prepending a given script to the scriptSig of vin 0 and # 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime -def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None): +def cltv_modify_tx(tx, prepend_scriptsig, nsequence=None, nlocktime=None): assert_equal(len(tx.vin), 1) if nsequence is not None: tx.vin[0].nSequence = nsequence @@ -45,10 +45,9 @@ def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None): tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(tx.vin[0].scriptSig))) tx.rehash() - return tx -def cltv_invalidate(node, tx, failure_reason): +def cltv_invalidate(tx, failure_reason): # Modify the signature in vin 0 and nSequence/nLockTime of the tx to fail CLTV # # According to BIP65, OP_CHECKLOCKTIMEVERIFY can fail due the following reasons: @@ -69,14 +68,14 @@ def cltv_invalidate(node, tx, failure_reason): [[CScriptNum(500), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 500], ][failure_reason] - return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2]) + cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2]) -def cltv_validate(node, tx, height): +def cltv_validate(tx, height): # Modify the signature in vin 0 and nSequence/nLockTime of the tx to pass CLTV scheme = [[CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, height] - return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2]) + cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2]) class BIP65Test(BitcoinTestFramework): @@ -111,17 +110,17 @@ class BIP65Test(BitcoinTestFramework): self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block") # create one invalid tx per CLTV failure reason (5 in total) and collect them - invalid_ctlv_txs = [] + invalid_cltv_txs = [] for i in range(5): spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx'] - spendtx = cltv_invalidate(self.nodes[0], spendtx, i) - invalid_ctlv_txs.append(spendtx) + cltv_invalidate(spendtx, i) + invalid_cltv_txs.append(spendtx) tip = self.nodes[0].getbestblockhash() block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1 block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time) block.nVersion = 3 - block.vtx.extend(invalid_ctlv_txs) + block.vtx.extend(invalid_cltv_txs) block.hashMerkleRoot = block.calc_merkle_root() block.solve() @@ -149,7 +148,7 @@ class BIP65Test(BitcoinTestFramework): # create and test one invalid tx per CLTV failure reason (5 in total) for i in range(5): spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx'] - spendtx = cltv_invalidate(self.nodes[0], spendtx, i) + cltv_invalidate(spendtx, i) expected_cltv_reject_reason = [ "non-mandatory-script-verify-flag (Operation not valid with the current stack size)", @@ -182,7 +181,7 @@ class BIP65Test(BitcoinTestFramework): peer.sync_with_ping() self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted") - spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1) + cltv_validate(spendtx, CLTV_HEIGHT - 1) block.vtx.pop(1) block.vtx.append(spendtx) diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py index d3adde5cc5..cf270b25ee 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -12,6 +12,7 @@ the index. from decimal import Decimal from test_framework.blocktools import ( + COINBASE_MATURITY, create_block, create_coinbase, ) @@ -68,7 +69,7 @@ class CoinStatsIndexTest(BitcoinTestFramework): index_hash_options = ['none', 'muhash'] # Generate a normal transaction and mine it - node.generate(101) + node.generate(COINBASE_MATURITY + 1) address = self.nodes[0].get_deterministic_priv_key().address node.sendtoaddress(address=address, amount=10, subtractfeefromamount=True) node.generate(1) diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py index 0a457ca17f..14f64d63a2 100755 --- a/test/functional/feature_loadblock.py +++ b/test/functional/feature_loadblock.py @@ -16,6 +16,7 @@ import sys import tempfile import urllib +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal @@ -28,7 +29,7 @@ class LoadblockTest(BitcoinTestFramework): def run_test(self): self.nodes[1].setnetworkactive(state=False) - self.nodes[0].generate(100) + self.nodes[0].generate(COINBASE_MATURITY) # Parsing the url of our node to get settings for config file data_dir = self.nodes[0].datadir diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index c7981d31dc..f467626801 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -14,15 +14,21 @@ Generate COINBASE_MATURITY (CB) more blocks to ensure the coinbases are mature. """ import time -from test_framework.blocktools import NORMAL_GBT_REQUEST_PARAMS, create_block, create_transaction, add_witness_commitment +from test_framework.blocktools import ( + COINBASE_MATURITY, + NORMAL_GBT_REQUEST_PARAMS, + add_witness_commitment, + create_block, + create_transaction, +) from test_framework.messages import CTransaction from test_framework.script import CScript from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error -COINBASE_MATURITY = 100 NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)" + def trueDummy(tx): scriptSig = CScript(tx.vin[0].scriptSig) newscript = [] @@ -35,18 +41,17 @@ def trueDummy(tx): tx.vin[0].scriptSig = CScript(newscript) tx.rehash() -class NULLDUMMYTest(BitcoinTestFramework): +class NULLDUMMYTest(BitcoinTestFramework): def set_test_params(self): - # Need two nodes so GBT (getblocktemplate) doesn't complain that it's not connected. - self.num_nodes = 2 + self.num_nodes = 1 self.setup_clean_chain = True # This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through # normal segwit activation here (and don't use the default always-on behaviour). self.extra_args = [[ f'-segwitheight={COINBASE_MATURITY + 5}', '-addresstype=legacy', - ]] * 2 + ]] def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py index 8bee43b8ad..162814815e 100755 --- a/test/functional/feature_proxy.py +++ b/test/functional/feature_proxy.py @@ -147,13 +147,13 @@ class ProxyTest(BitcoinTestFramework): self.network_test(node, addr, network=NET_IPV6) if test_onion: - addr = "bitcoinostk4e4re.onion:8333" + addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333" self.log.debug("Test: outgoing onion connection through node for address {}".format(addr)) node.addnode(addr, "onetry") cmd = proxies[2].queue.get() assert isinstance(cmd, Socks5Command) assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, b"bitcoinostk4e4re.onion") + assert_equal(cmd.addr, b"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion") assert_equal(cmd.port, 8333) if not auth: assert_equal(cmd.username, None) diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 945880cc3b..344db5f652 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -6,6 +6,7 @@ from decimal import Decimal +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut from test_framework.script import CScript, OP_DROP from test_framework.test_framework import BitcoinTestFramework @@ -27,7 +28,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT): """ fee = 1*COIN while node.getbalance() < satoshi_round((amount + fee)/COIN): - node.generate(100) + node.generate(COINBASE_MATURITY) new_addr = node.getnewaddress() txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN)) diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index 183a43abd4..fc04853199 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -5,6 +5,7 @@ # Test Taproot softfork (BIPs 340-342) from test_framework.blocktools import ( + COINBASE_MATURITY, create_coinbase, create_block, add_witness_commitment, @@ -1440,7 +1441,7 @@ class TaprootTest(BitcoinTestFramework): def run_test(self): # Post-taproot activation tests go first (pre-taproot tests' blocks are invalid post-taproot). self.log.info("Post-activation tests...") - self.nodes[1].generate(101) + self.nodes[1].generate(COINBASE_MATURITY + 1) self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3]) # Re-connect nodes in case they have been disconnected diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index b5ce18a48b..30cd499b3f 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -5,6 +5,8 @@ """Test bitcoin-cli""" from decimal import Decimal + +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -16,7 +18,7 @@ from test_framework.util import ( # The block reward of coinbaseoutput.nValue (50) BTC/block matures after # COINBASE_MATURITY (100) blocks. Therefore, after mining 101 blocks we expect # node 0 to have a balance of (BLOCKS - COINBASE_MATURITY) * 50 BTC/block. -BLOCKS = 101 +BLOCKS = COINBASE_MATURITY + 1 BALANCE = (BLOCKS - 100) * 50 JSON_PARSING_ERROR = 'error: Error parsing JSON: foo' diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index eb08765ebf..6de6778909 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -15,6 +15,7 @@ Only v0.15.2 is required by this test. The rest is used in other backwards compa import os +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.wallet import MiniWallet @@ -41,7 +42,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework): old_node, new_node = self.nodes new_wallet = MiniWallet(new_node) new_wallet.generate(1) - new_node.generate(100) + new_node.generate(COINBASE_MATURITY) # Sync the nodes to ensure old_node has the block that contains the coinbase that new_wallet will spend. # Otherwise, because coinbases are only valid in a block and not as loose txns, if the nodes aren't synced # unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`. diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py index 4c46075ae9..7d1bfef333 100755 --- a/test/functional/mempool_expiry.py +++ b/test/functional/mempool_expiry.py @@ -12,6 +12,7 @@ definable expiry timeout via the '-mempoolexpiry=<n>' command line argument from datetime import timedelta +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -36,7 +37,7 @@ class MempoolExpiryTest(BitcoinTestFramework): # Add enough mature utxos to the wallet so that all txs spend confirmed coins. self.wallet.generate(4) - node.generate(100) + node.generate(COINBASE_MATURITY) # Send a parent transaction that will expire. parent_txid = self.wallet.send_self_transfer(from_node=node)['txid'] diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py index 884a2fef11..1e9895e621 100755 --- a/test/functional/mempool_package_onemore.py +++ b/test/functional/mempool_package_onemore.py @@ -9,6 +9,7 @@ from decimal import Decimal +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round @@ -42,7 +43,7 @@ class MempoolPackagesTest(BitcoinTestFramework): def run_test(self): # Mine some blocks and have them mature. - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) utxo = self.nodes[0].listunspent(10) txid = utxo[0]['txid'] vout = utxo[0]['vout'] diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index 461f9237ff..606717d890 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -6,6 +6,7 @@ from decimal import Decimal +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import COIN from test_framework.p2p import P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework @@ -59,7 +60,7 @@ class MempoolPackagesTest(BitcoinTestFramework): def run_test(self): # Mine some blocks and have them mature. peer_inv_store = self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) utxo = self.nodes[0].listunspent(10) txid = utxo[0]['txid'] vout = utxo[0]['vout'] diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 8e1f87e42c..bcc6aa7bcc 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -8,10 +8,9 @@ Test re-org scenarios with a mempool that contains transactions that spend (directly or indirectly) coinbase transactions. """ -from test_framework.blocktools import create_raw_transaction from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error - +from test_framework.wallet import MiniWallet class MempoolCoinbaseTest(BitcoinTestFramework): def set_test_params(self): @@ -23,86 +22,90 @@ class MempoolCoinbaseTest(BitcoinTestFramework): [] ] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): + wallet = MiniWallet(self.nodes[0]) + # Start with a 200 block chain assert_equal(self.nodes[0].getblockcount(), 200) - # Mine four blocks. After this, nodes[0] blocks - # 101, 102, and 103 are spend-able. - new_blocks = self.nodes[1].generate(4) - self.sync_all() - - node0_address = self.nodes[0].getnewaddress() - node1_address = self.nodes[1].getnewaddress() + self.log.info("Add 4 coinbase utxos to the miniwallet") + # Block 76 contains the first spendable coinbase txs. + first_block = 76 + wallet.scan_blocks(start=first_block, num=4) # Three scenarios for re-orging coinbase spends in the memory pool: - # 1. Direct coinbase spend : spend_101 - # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1 - # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1 - # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase), + # 1. Direct coinbase spend : spend_1 + # 2. Indirect (coinbase spend in chain, child in mempool) : spend_2 and spend_2_1 + # 3. Indirect (coinbase and child both in chain) : spend_3 and spend_3_1 + # Use invalidateblock to make all of the above coinbase spends invalid (immature coinbase), # and make sure the mempool code behaves correctly. - b = [self.nodes[0].getblockhash(n) for n in range(101, 105)] + b = [self.nodes[0].getblockhash(n) for n in range(first_block, first_block+4)] coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b] - spend_101_raw = create_raw_transaction(self.nodes[0], coinbase_txids[1], node1_address, amount=49.99) - spend_102_raw = create_raw_transaction(self.nodes[0], coinbase_txids[2], node0_address, amount=49.99) - spend_103_raw = create_raw_transaction(self.nodes[0], coinbase_txids[3], node0_address, amount=49.99) - - # Create a transaction which is time-locked to two blocks in the future - timelock_tx = self.nodes[0].createrawtransaction( - inputs=[{ - "txid": coinbase_txids[0], - "vout": 0, - }], - outputs={node0_address: 49.99}, - locktime=self.nodes[0].getblockcount() + 2, - ) - timelock_tx = self.nodes[0].signrawtransactionwithwallet(timelock_tx)["hex"] - # This will raise an exception because the timelock transaction is too immature to spend + utxo_1 = wallet.get_utxo(txid=coinbase_txids[1]) + utxo_2 = wallet.get_utxo(txid=coinbase_txids[2]) + utxo_3 = wallet.get_utxo(txid=coinbase_txids[3]) + self.log.info("Create three transactions spending from coinbase utxos: spend_1, spend_2, spend_3") + spend_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_1) + spend_2 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_2) + spend_3 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_3) + + self.log.info("Create another transaction which is time-locked to two blocks in the future") + utxo = wallet.get_utxo(txid=coinbase_txids[0]) + timelock_tx = wallet.create_self_transfer( + from_node=self.nodes[0], + utxo_to_spend=utxo, + mempool_valid=False, + locktime=self.nodes[0].getblockcount() + 2 + )['hex'] + + self.log.info("Check that the time-locked transaction is too immature to spend") assert_raises_rpc_error(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx) - # Broadcast and mine spend_102 and 103: - spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) - spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) + self.log.info("Broadcast and mine spend_2 and spend_3") + wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=spend_2['hex']) + wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=spend_3['hex']) + self.log.info("Generate a block") self.nodes[0].generate(1) - # Time-locked transaction is still too immature to spend + self.log.info("Check that time-locked transaction is still too immature to spend") assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, timelock_tx) - # Create 102_1 and 103_1: - spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id, node1_address, amount=49.98) - spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id, node1_address, amount=49.98) + self.log.info("Create spend_2_1 and spend_3_1") + spend_2_utxo = wallet.get_utxo(txid=spend_2['txid']) + spend_2_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_2_utxo) + spend_3_utxo = wallet.get_utxo(txid=spend_3['txid']) + spend_3_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_3_utxo) - # Broadcast and mine 103_1: - spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) + self.log.info("Broadcast and mine spend_3_1") + spend_3_1_id = self.nodes[0].sendrawtransaction(spend_3_1['hex']) + self.log.info("Generate a block") last_block = self.nodes[0].generate(1) # Sync blocks, so that peer 1 gets the block before timelock_tx # Otherwise, peer 1 would put the timelock_tx in recentRejects self.sync_all() - # Time-locked transaction can now be spent + self.log.info("The time-locked transaction can now be spent") timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx) - # ... now put spend_101 and spend_102_1 in memory pools: - spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) - spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw) + self.log.info("Add spend_1 and spend_2_1 to the mempool") + spend_1_id = self.nodes[0].sendrawtransaction(spend_1['hex']) + spend_2_1_id = self.nodes[0].sendrawtransaction(spend_2_1['hex']) - assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id}) + assert_equal(set(self.nodes[0].getrawmempool()), {spend_1_id, spend_2_1_id, timelock_tx_id}) self.sync_all() + self.log.info("invalidate the last block") for node in self.nodes: node.invalidateblock(last_block[0]) - # Time-locked transaction is now too immature and has been removed from the mempool - # spend_103_1 has been re-orged out of the chain and is back in the mempool - assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id}) + self.log.info("The time-locked transaction is now too immature and has been removed from the mempool") + self.log.info("spend_3_1 has been re-orged out of the chain and is back in the mempool") + assert_equal(set(self.nodes[0].getrawmempool()), {spend_1_id, spend_2_1_id, spend_3_1_id}) - # Use invalidateblock to re-org back and make all those coinbase spends - # immature/invalid: + self.log.info("Use invalidateblock to re-org back and make all those coinbase spends immature/invalid") + b = self.nodes[0].getblockhash(first_block + 100) for node in self.nodes: - node.invalidateblock(new_blocks[0]) + node.invalidateblock(b) - # mempool should be empty. + self.log.info("Check that the mempool is empty") assert_equal(set(self.nodes[0].getrawmempool()), set()) self.sync_all() diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py index 4aa58270b6..1b5ca7e15a 100755 --- a/test/functional/mempool_resurrect.py +++ b/test/functional/mempool_resurrect.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test resurrection of mined transactions when the blockchain is re-organized.""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal from test_framework.wallet import MiniWallet @@ -20,7 +21,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Add enough mature utxos to the wallet so that all txs spend confirmed coins wallet.generate(3) - node.generate(100) + node.generate(COINBASE_MATURITY) # Spend block 1/2/3's coinbase transactions # Mine a block diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py index cc32f78e2e..715b68e04c 100755 --- a/test/functional/mining_getblocktemplate_longpoll.py +++ b/test/functional/mining_getblocktemplate_longpoll.py @@ -8,6 +8,7 @@ from decimal import Decimal import random import threading +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import get_rpc_proxy from test_framework.wallet import MiniWallet @@ -62,7 +63,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): assert not thr.is_alive() # Add enough mature utxos to the wallets, so that all txs spend confirmed coins - self.nodes[0].generate(100) + self.nodes[0].generate(COINBASE_MATURITY) self.sync_blocks() self.log.info("Test that introducing a new transaction into the mempool will terminate the longpoll") diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index ab2556cd72..6409d4ea82 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -6,6 +6,7 @@ import time +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import msg_tx from test_framework.p2p import P2PInterface, P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework @@ -23,7 +24,7 @@ class P2PBlocksOnly(BitcoinTestFramework): self.miniwallet = MiniWallet(self.nodes[0]) # Add enough mature utxos to the wallet, so that all txs spend confirmed coins self.miniwallet.generate(2) - self.nodes[0].generate(100) + self.nodes[0].generate(COINBASE_MATURITY) self.blocksonly_mode_tests() self.blocks_relay_conn_tests() diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 55573efc06..3e4f2f974d 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -9,7 +9,12 @@ Version 2 compact blocks are post-segwit (wtxids) """ import random -from test_framework.blocktools import create_block, NORMAL_GBT_REQUEST_PARAMS, add_witness_commitment +from test_framework.blocktools import ( + COINBASE_MATURITY, + NORMAL_GBT_REQUEST_PARAMS, + add_witness_commitment, + create_block, +) from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_BLOCK, MSG_CMPCT_BLOCK, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex from test_framework.p2p import p2p_lock, P2PInterface from test_framework.script import CScript, OP_TRUE, OP_DROP @@ -115,7 +120,7 @@ class CompactBlocksTest(BitcoinTestFramework): block = self.build_block_on_tip(self.nodes[0]) self.segwit_node.send_and_ping(msg_no_witness_block(block)) assert int(self.nodes[0].getbestblockhash(), 16) == block.sha256 - self.nodes[0].generatetoaddress(100, self.nodes[0].getnewaddress(address_type="bech32")) + self.nodes[0].generatetoaddress(COINBASE_MATURITY, self.nodes[0].getnewaddress(address_type="bech32")) total_value = block.vtx[0].vout[0].nValue out_value = total_value // 10 @@ -226,7 +231,7 @@ class CompactBlocksTest(BitcoinTestFramework): # This test actually causes bitcoind to (reasonably!) disconnect us, so do this last. def test_invalid_cmpctblock_message(self): - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) block = self.build_block_on_tip(self.nodes[0]) cmpct_block = P2PHeaderAndShortIDs() @@ -244,7 +249,7 @@ class CompactBlocksTest(BitcoinTestFramework): version = test_node.cmpct_version node = self.nodes[0] # Generate a bunch of transactions. - node.generate(101) + node.generate(COINBASE_MATURITY + 1) num_transactions = 25 address = node.getnewaddress() diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py index d60aa5b383..a525996493 100755 --- a/test/functional/p2p_eviction.py +++ b/test/functional/p2p_eviction.py @@ -15,7 +15,11 @@ Therefore, this test is limited to the remaining protection criteria. import time -from test_framework.blocktools import create_block, create_coinbase +from test_framework.blocktools import ( + COINBASE_MATURITY, + create_block, + create_coinbase, +) from test_framework.messages import CTransaction, FromHex, msg_pong, msg_tx from test_framework.p2p import P2PDataStore, P2PInterface from test_framework.test_framework import BitcoinTestFramework @@ -45,7 +49,7 @@ class P2PEvict(BitcoinTestFramework): protected_peers = set() # peers that we expect to be protected from eviction current_peer = -1 node = self.nodes[0] - node.generatetoaddress(101, node.get_deterministic_priv_key().address) + node.generatetoaddress(COINBASE_MATURITY + 1, node.get_deterministic_priv_key().address) self.log.info("Create 4 peers and protect them from eviction by sending us a block") for _ in range(4): diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py index 52dc4de3bd..0175b9f6c0 100755 --- a/test/functional/p2p_feefilter.py +++ b/test/functional/p2p_feefilter.py @@ -6,6 +6,7 @@ from decimal import Decimal +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter from test_framework.p2p import P2PInterface, p2p_lock from test_framework.test_framework import BitcoinTestFramework @@ -81,7 +82,7 @@ class FeeFilterTest(BitcoinTestFramework): miniwallet = MiniWallet(node1) # Add enough mature utxos to the wallet, so that all txs spend confirmed coins miniwallet.generate(5) - node1.generate(100) + node1.generate(COINBASE_MATURITY) conn = self.nodes[0].add_p2p_connection(TestP2PConn()) diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 71d5ca92b3..f1538e8ac7 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -29,6 +29,8 @@ from test_framework.util import ( assert_greater_than_or_equal, ) +PEER_TIMEOUT = 3 + class LazyPeer(P2PInterface): def __init__(self): @@ -98,7 +100,7 @@ class P2PVersionStore(P2PInterface): class P2PLeakTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [['-peertimeout=4']] + self.extra_args = [[f"-peertimeout={PEER_TIMEOUT}"]] def create_old_version(self, nversion): old_version_msg = msg_version() @@ -134,7 +136,7 @@ class P2PLeakTest(BitcoinTestFramework): self.nodes[0].generate(nblocks=1) # Give the node enough time to possibly leak out a message - time.sleep(5) + time.sleep(PEER_TIMEOUT + 2) # Make sure only expected messages came in assert not no_version_idle_peer.unexpected_msg diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py index a45f792e81..9a4ceb86ae 100755 --- a/test/functional/p2p_leak_tx.py +++ b/test/functional/p2p_leak_tx.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test that we don't leak txs to inbound peers that we haven't yet announced to""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import msg_getdata, CInv, MSG_TX from test_framework.p2p import p2p_lock, P2PDataStore from test_framework.test_framework import BitcoinTestFramework @@ -27,7 +28,7 @@ class P2PLeakTxTest(BitcoinTestFramework): miniwallet = MiniWallet(gen_node) # Add enough mature utxos to the wallet, so that all txs spend confirmed coins miniwallet.generate(1) - gen_node.generate(100) + gen_node.generate(COINBASE_MATURITY) inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 19f0d5765a..af515f3a27 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -9,6 +9,7 @@ import itertools import json import os +from test_framework.blocktools import COINBASE_MATURITY from test_framework.authproxy import JSONRPCException from test_framework.descriptors import descsum_create, drop_origins from test_framework.key import ECPubKey, ECKey @@ -109,7 +110,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def checkbalances(self): node0, node1, node2 = self.nodes - node0.generate(100) + node0.generate(COINBASE_MATURITY) self.sync_all() bal0 = node0.getbalance() diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py index dc469ba552..3efbdab013 100755 --- a/test/functional/rpc_dumptxoutset.py +++ b/test/functional/rpc_dumptxoutset.py @@ -4,6 +4,8 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the generation of UTXO snapshots using `dumptxoutset`. """ + +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error @@ -21,7 +23,7 @@ class DumptxoutsetTest(BitcoinTestFramework): node = self.nodes[0] mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) - node.generate(100) + node.generate(COINBASE_MATURITY) FILENAME = 'txoutset.dat' out = node.dumptxoutset(FILENAME) diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index 57794ae973..4af518c870 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -6,6 +6,8 @@ # # Test getblockstats rpc call # + +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -41,7 +43,7 @@ class GetblockstatsTest(BitcoinTestFramework): def generate_test_data(self, filename): mocktime = 1525107225 self.nodes[0].setmocktime(mocktime) - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) address = self.nodes[0].get_deterministic_priv_key().address self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 9a2817a6ee..6e5ef770d1 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -11,6 +11,7 @@ from decimal import Decimal from itertools import product import time +from test_framework.blocktools import COINBASE_MATURITY from test_framework.p2p import P2PInterface import test_framework.messages from test_framework.messages import ( @@ -53,7 +54,7 @@ class NetTest(BitcoinTestFramework): self.wallet = MiniWallet(self.nodes[0]) self.wallet.generate(1) # Get out of IBD for the minfeefilter and getpeerinfo tests. - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) # By default, the test framework sets up an addnode connection from # node 1 --> node0. By connecting node0 --> node 1, we're left with diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 86c7b3fbcc..53ddf24e47 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -15,6 +15,8 @@ Test the following RPCs: from collections import OrderedDict from decimal import Decimal from io import BytesIO + +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import CTransaction, ToHex from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -66,7 +68,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.log.info('prepare some coins for multiple *rawtransaction commands') self.nodes[2].generate(1) self.sync_all() - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) self.sync_all() self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0) diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 60b4d1c744..16b0019866 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test transaction signing using the signrawtransaction* RPCs.""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.address import check_script, script_to_p2sh, script_to_p2wsh from test_framework.key import ECKey from test_framework.test_framework import BitcoinTestFramework @@ -155,7 +156,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): def test_fully_signed_tx(self): self.log.info("Test signing a fully signed transaction does nothing") self.nodes[0].walletpassphrase("password", 9999) - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) rawtx = self.nodes[0].createrawtransaction([], [{self.nodes[0].getnewaddress(): 10}]) fundedtx = self.nodes[0].fundrawtransaction(rawtx) signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx["hex"]) @@ -174,7 +175,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): embedded_pubkey = eckey.get_pubkey().get_bytes().hex() p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey], "p2sh-segwit") # send transaction to P2SH-P2WSH 1-of-1 multisig address - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) self.nodes[0].sendtoaddress(p2sh_p2wsh_address["address"], 49.999) self.nodes[0].generate(1) self.sync_all() diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index 528da0cbfc..bf96b6353c 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test gettxoutproof and verifytxoutproof RPCs.""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import CMerkleBlock, FromHex, ToHex from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error @@ -23,7 +24,7 @@ class MerkleBlockTest(BitcoinTestFramework): miniwallet = MiniWallet(self.nodes[0]) # Add enough mature utxos to the wallet, so that all txs spend confirmed coins miniwallet.generate(5) - self.nodes[0].generate(100) + self.nodes[0].generate(COINBASE_MATURITY) self.sync_all() chain_height = self.nodes[1].getblockcount() diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index d08e025178..e91b44e776 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -52,6 +52,9 @@ MAX_BLOCK_SIGOPS_WEIGHT = MAX_BLOCK_SIGOPS * WITNESS_SCALE_FACTOR # Genesis block time (regtest) TIME_GENESIS_BLOCK = 1296688602 +# Coinbase transaction outputs can only be spent after this number of new blocks (network rule) +COINBASE_MATURITY = 100 + # From BIP141 WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed" diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index e047e7fa14..5dc723c1d5 100644 --- a/test/functional/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py @@ -151,7 +151,7 @@ def test_ipv6_local(): have_ipv6 = True try: s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - s.connect(('::1', 0)) + s.connect(('::1', 1)) except socket.error: have_ipv6 = False return have_ipv6 diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 05bda5d899..bfb5916c37 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -123,13 +123,13 @@ class MiniWallet: else: return self._utxos[index] - def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None): + def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, locktime=0): """Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" tx = self.create_self_transfer(fee_rate=fee_rate, from_node=from_node, utxo_to_spend=utxo_to_spend) self.sendrawtransaction(from_node=from_node, tx_hex=tx['hex']) return tx - def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True): + def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0): """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" self._utxos = sorted(self._utxos, key=lambda k: k['value']) utxo_to_spend = utxo_to_spend or self._utxos.pop() # Pick the largest utxo (if none provided) and hope it covers the fee @@ -141,6 +141,7 @@ class MiniWallet: tx = CTransaction() tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))] tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)] + tx.nLockTime = locktime if not self._address: # raw script if self._priv_key is not None: diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 49f269f8b4..c9a8cc5611 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -261,6 +261,7 @@ BASE_SCRIPTS = [ 'wallet_send.py --legacy-wallet', 'wallet_send.py --descriptors', 'wallet_create_tx.py --descriptors', + 'wallet_taproot.py', 'p2p_fingerprint.py', 'feature_uacomment.py', 'wallet_coinbase_category.py --legacy-wallet', @@ -283,6 +284,7 @@ BASE_SCRIPTS = [ 'feature_logging.py', 'feature_anchors.py', 'feature_coinstatsindex.py', + 'wallet_orphanedreward.py', 'p2p_node_network_limited.py', 'p2p_permissions.py', 'feature_blocksdir.py', diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index 2e0edcfa38..d24cc802a4 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -12,6 +12,7 @@ """ from decimal import Decimal +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -28,7 +29,7 @@ class AbandonConflictTest(BitcoinTestFramework): self.skip_if_no_wallet() def run_test(self): - self.nodes[1].generate(100) + self.nodes[1].generate(COINBASE_MATURITY) self.sync_blocks() balance = self.nodes[0].getbalance() txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index b3bee1876d..6d93cf412f 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -53,6 +53,7 @@ Test that the nodes generate the correct change address type: from decimal import Decimal import itertools +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.descriptors import ( descsum_create, @@ -220,7 +221,7 @@ class AddressTypeTest(BitcoinTestFramework): def run_test(self): # Mine 101 blocks on node5 to bring nodes out of IBD and make sure that # no coinbases are maturing for the nodes-under-test during the test - self.nodes[5].generate(101) + self.nodes[5].generate(COINBASE_MATURITY + 1) self.sync_blocks() uncompressed_1 = "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee" @@ -258,7 +259,7 @@ class AddressTypeTest(BitcoinTestFramework): self.log.info("Sending from node {} ({}) with{} multisig using {}".format(from_node, self.extra_args[from_node], "" if multisig else "out", "default" if address_type is None else address_type)) old_balances = self.get_balances() self.log.debug("Old balances are {}".format(old_balances)) - to_send = (old_balances[from_node] / 101).quantize(Decimal("0.00000001")) + to_send = (old_balances[from_node] / (COINBASE_MATURITY + 1)).quantize(Decimal("0.00000001")) sends = {} addresses = {} diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index f34c1345e0..05a0ef0ea1 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -35,6 +35,7 @@ import os from random import randint import shutil +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -123,7 +124,7 @@ class WalletBackupTest(BitcoinTestFramework): self.sync_blocks() self.nodes[2].generate(1) self.sync_blocks() - self.nodes[3].generate(100) + self.nodes[3].generate(COINBASE_MATURITY) self.sync_blocks() assert_equal(self.nodes[0].getbalance(), 50) @@ -152,7 +153,7 @@ class WalletBackupTest(BitcoinTestFramework): self.do_one_round() # Generate 101 more blocks, so any fees paid mature - self.nodes[3].generate(101) + self.nodes[3].generate(COINBASE_MATURITY + 1) self.sync_all() balance0 = self.nodes[0].getbalance() diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index 433b40faee..204a866c55 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -7,6 +7,7 @@ from decimal import Decimal import struct from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE as ADDRESS_WATCHONLY +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -72,7 +73,7 @@ class WalletTest(BitcoinTestFramework): self.nodes[0].generate(1) self.sync_all() self.nodes[1].generate(1) - self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY) + self.nodes[1].generatetoaddress(COINBASE_MATURITY + 1, ADDRESS_WATCHONLY) self.sync_all() if not self.options.descriptors: diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 4a1d25bbc5..a052ec7477 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -6,6 +6,7 @@ from decimal import Decimal from itertools import product +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_array_result, @@ -65,7 +66,7 @@ class WalletTest(BitcoinTestFramework): assert_equal(walletinfo['balance'], 0) self.sync_all(self.nodes[0:3]) - self.nodes[1].generate(101) + self.nodes[1].generate(COINBASE_MATURITY + 1) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 50) @@ -158,7 +159,7 @@ class WalletTest(BitcoinTestFramework): assert_equal(len(self.nodes[1].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) - self.nodes[1].generate(100) + self.nodes[1].generate(COINBASE_MATURITY) self.sync_all(self.nodes[0:3]) # node0 should end up with 100 btc in block rewards plus fees, but diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index ff5070c1fa..b21461ee7b 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -16,6 +16,7 @@ make assumptions about execution order. from decimal import Decimal import io +from test_framework.blocktools import COINBASE_MATURITY from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction from test_framework.test_framework import BitcoinTestFramework @@ -265,7 +266,7 @@ def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): self.log.info('Testing small output with feerate bump succeeds') # Make sure additional inputs exist - rbf_node.generatetoaddress(101, rbf_node.getnewaddress()) + rbf_node.generatetoaddress(COINBASE_MATURITY + 1, rbf_node.getnewaddress()) rbfid = spend_one_input(rbf_node, dest_address) input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"] assert_equal(len(input_list), 1) diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index 1e032bdd6c..c6f5d334f8 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test descriptor wallet function.""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -83,7 +84,7 @@ class WalletDescriptorTest(BitcoinTestFramework): send_wrpc = self.nodes[0].get_wallet_rpc("desc1") # Generate some coins - send_wrpc.generatetoaddress(101, send_wrpc.getnewaddress()) + send_wrpc.generatetoaddress(COINBASE_MATURITY + 1, send_wrpc.getnewaddress()) # Make transactions self.log.info("Test sending and receiving") diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py index 78eef4b790..b28f3ecebc 100755 --- a/test/functional/wallet_fallbackfee.py +++ b/test/functional/wallet_fallbackfee.py @@ -3,6 +3,8 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test wallet replace-by-fee capabilities in conjunction with the fallbackfee.""" + +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_raises_rpc_error @@ -15,7 +17,7 @@ class WalletRBFTest(BitcoinTestFramework): self.skip_if_no_wallet() def run_test(self): - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) # sending a transaction without fee estimations must be possible by default on regtest self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index c0b76d960f..f32acb8e15 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test wallet group functionality.""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import CTransaction, FromHex, ToHex from test_framework.util import ( @@ -31,7 +32,7 @@ class WalletGroupTest(BitcoinTestFramework): def run_test(self): self.log.info("Setting up") # Mine some coins - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) # Get some addresses from the two nodes addr1 = [self.nodes[1].getnewaddress() for _ in range(3)] diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 23d132df41..d41a389197 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -7,6 +7,7 @@ import os import shutil +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -48,7 +49,7 @@ class WalletHDTest(BitcoinTestFramework): # Derive some HD addresses and remember the last # Also send funds to each add - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) hd_add = None NUM_HD_ADDS = 10 for i in range(1, NUM_HD_ADDS + 1): diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py index 0a3dd56620..a2da16e5a3 100755 --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -16,6 +16,7 @@ variants. and test the values returned.""" from test_framework.address import key_to_p2pkh +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.descriptors import descsum_create from test_framework.util import ( @@ -73,7 +74,7 @@ class ImportDescriptorsTest(BitcoinTestFramework): assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0) self.log.info('Mining coins') - w0.generatetoaddress(101, w0.getnewaddress()) + w0.generatetoaddress(COINBASE_MATURITY + 1, w0.getnewaddress()) # RPC importdescriptors ----------------------------------------------- diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 13186b9e1d..0a00c5eed9 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -15,6 +15,7 @@ variants. - `test_address()` is called to call getaddressinfo for an address on node1 and test the values returned.""" +from test_framework.blocktools import COINBASE_MATURITY from test_framework.script import ( CScript, OP_NOP, @@ -255,7 +256,7 @@ class ImportMultiTest(BitcoinTestFramework): # P2SH address multisig = get_multisig(self.nodes[0]) - self.nodes[1].generate(100) + self.nodes[1].generate(COINBASE_MATURITY) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] @@ -276,7 +277,7 @@ class ImportMultiTest(BitcoinTestFramework): # P2SH + Redeem script multisig = get_multisig(self.nodes[0]) - self.nodes[1].generate(100) + self.nodes[1].generate(COINBASE_MATURITY) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] @@ -297,7 +298,7 @@ class ImportMultiTest(BitcoinTestFramework): # P2SH + Redeem script + Private Keys + !Watchonly multisig = get_multisig(self.nodes[0]) - self.nodes[1].generate(100) + self.nodes[1].generate(COINBASE_MATURITY) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] @@ -323,7 +324,7 @@ class ImportMultiTest(BitcoinTestFramework): # P2SH + Redeem script + Private Keys + Watchonly multisig = get_multisig(self.nodes[0]) - self.nodes[1].generate(100) + self.nodes[1].generate(COINBASE_MATURITY) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.nodes[1].generate(1) timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py index 7635ce2139..ded0e64b1d 100755 --- a/test/functional/wallet_importprunedfunds.py +++ b/test/functional/wallet_importprunedfunds.py @@ -5,6 +5,7 @@ """Test the importprunedfunds and removeprunedfunds RPCs.""" from decimal import Decimal +from test_framework.blocktools import COINBASE_MATURITY from test_framework.address import key_to_p2wpkh from test_framework.key import ECKey from test_framework.test_framework import BitcoinTestFramework @@ -24,7 +25,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): def run_test(self): self.log.info("Mining blocks...") - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) self.sync_all() @@ -46,7 +47,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): self.sync_all() # Node 1 sync test - assert_equal(self.nodes[1].getblockcount(), 101) + assert_equal(self.nodes[1].getblockcount(), COINBASE_MATURITY + 1) # Address Test - before import address_info = self.nodes[1].getaddressinfo(address1) diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index 5619d57947..1ecf08b9ac 100755 --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -13,6 +13,7 @@ Two nodes. Node1 is under test. Node0 is providing transactions and generating b import os import shutil +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -31,7 +32,7 @@ class KeypoolRestoreTest(BitcoinTestFramework): def run_test(self): wallet_path = os.path.join(self.nodes[1].datadir, self.chain, "wallets", self.default_wallet_name, self.wallet_data_filename) wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak") - self.nodes[0].generate(101) + self.nodes[0].generate(COINBASE_MATURITY + 1) self.log.info("Make backup of wallet") self.stop_node(1) diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py index 551eb72720..2d792bac52 100755 --- a/test/functional/wallet_labels.py +++ b/test/functional/wallet_labels.py @@ -11,6 +11,7 @@ RPCs tested are: """ from collections import defaultdict +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error from test_framework.wallet_util import test_address @@ -32,7 +33,7 @@ class WalletLabelsTest(BitcoinTestFramework): # Note each time we call generate, all generated coins go into # the same address, so we call twice to get two addresses w/50 each node.generatetoaddress(nblocks=1, address=node.getnewaddress(label='coinbase')) - node.generatetoaddress(nblocks=101, address=node.getnewaddress(label='coinbase')) + node.generatetoaddress(nblocks=COINBASE_MATURITY + 1, address=node.getnewaddress(label='coinbase')) assert_equal(node.getbalance(), 100) # there should be 2 address groups @@ -104,7 +105,7 @@ class WalletLabelsTest(BitcoinTestFramework): label.verify(node) assert_equal(node.getreceivedbylabel(label.name), 2) label.verify(node) - node.generate(101) + node.generate(COINBASE_MATURITY + 1) # Check that setlabel can assign a label to a new unused address. for label in labels: @@ -124,7 +125,7 @@ class WalletLabelsTest(BitcoinTestFramework): label.add_address(multisig_address) label.purpose[multisig_address] = "send" label.verify(node) - node.generate(101) + node.generate(COINBASE_MATURITY + 1) # Check that setlabel can change the label of an address from a # different label. diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index 448720530c..3899971bd7 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -5,6 +5,7 @@ """Test the listsinceblock RPC.""" from test_framework.address import key_to_p2wpkh +from test_framework.blocktools import COINBASE_MATURITY from test_framework.key import ECKey from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import BIP125_SEQUENCE_NUMBER @@ -29,7 +30,7 @@ class ListSinceBlockTest(BitcoinTestFramework): # All nodes are in IBD from genesis, so they'll need the miner (node2) to be an outbound connection, or have # only one connection. (See fPreferredDownload in net_processing) self.connect_nodes(1, 2) - self.nodes[2].generate(101) + self.nodes[2].generate(COINBASE_MATURITY + 1) self.sync_all() self.test_no_blockhash() diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 71d1b96a95..00d2c9ffe4 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -14,6 +14,7 @@ import stat import time from test_framework.authproxy import JSONRPCException +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.test_node import ErrorMatch from test_framework.util import ( @@ -229,7 +230,7 @@ class MultiWalletTest(BitcoinTestFramework): assert_raises_rpc_error(-19, "Wallet file not specified", node.getwalletinfo) w1, w2, w3, w4, *_ = wallets - node.generatetoaddress(nblocks=101, address=w1.getnewaddress()) + node.generatetoaddress(nblocks=COINBASE_MATURITY + 1, address=w1.getnewaddress()) assert_equal(w1.getbalance(), 100) assert_equal(w2.getbalance(), 0) assert_equal(w3.getbalance(), 0) diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py new file mode 100755 index 0000000000..e1544cbb48 --- /dev/null +++ b/test/functional/wallet_orphanedreward.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020-2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test orphaned block rewards in the wallet.""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +class OrphanedBlockRewardTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 2 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + # Generate some blocks and obtain some coins on node 0. We send + # some balance to node 1, which will hold it as a single coin. + self.nodes[0].generate(150) + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) + self.nodes[0].generate(1) + + # Get a block reward with node 1 and remember the block so we can orphan + # it later. + self.sync_blocks() + blk = self.nodes[1].generate(1)[0] + self.sync_blocks() + + # Let the block reward mature and send coins including both + # the existing balance and the block reward. + self.nodes[0].generate(150) + assert_equal(self.nodes[1].getbalance(), 10 + 25) + txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 30) + + # Orphan the block reward and make sure that the original coins + # from the wallet can still be spent. + self.nodes[0].invalidateblock(blk) + self.nodes[0].generate(152) + self.sync_blocks() + # Without the following abandontransaction call, the coins are + # not considered available yet. + assert_equal(self.nodes[1].getbalances()["mine"], { + "trusted": 0, + "untrusted_pending": 0, + "immature": 0, + }) + # The following abandontransaction is necessary to make the later + # lines succeed, and probably should not be needed; see + # https://github.com/bitcoin/bitcoin/issues/14148. + self.nodes[1].abandontransaction(txid) + assert_equal(self.nodes[1].getbalances()["mine"], { + "trusted": 10, + "untrusted_pending": 0, + "immature": 0, + }) + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 9) + +if __name__ == '__main__': + OrphanedBlockRewardTest().main() diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py new file mode 100755 index 0000000000..65ca7bdef7 --- /dev/null +++ b/test/functional/wallet_taproot.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test generation and spending of P2TR addresses.""" + +import random + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal +from test_framework.descriptors import descsum_create +from test_framework.script import (CScript, OP_CHECKSIG, taproot_construct) +from test_framework.segwit_addr import encode_segwit_address + +# xprvs/xpubs, and m/* derived x-only pubkeys (created using independent implementation) +KEYS = [ + { + "xprv": "tprv8ZgxMBicQKsPeNLUGrbv3b7qhUk1LQJZAGMuk9gVuKh9sd4BWGp1eMsehUni6qGb8bjkdwBxCbgNGdh2bYGACK5C5dRTaif9KBKGVnSezxV", + "xpub": "tpubD6NzVbkrYhZ4XqNGAWGWSzmxGWFwVjVTjZxh2fioKbVYi7Jx8fdbprVWsdW7mHwqjchBVas8TLZG4Xwuz4RKU4iaCqiCvoSkFCzQptqk5Y1", + "pubs": [ + "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18", + "a30253b018ea6fca966135bf7dd8026915427f24ccf10d4e03f7870f4128569b", + "a61e5749f2f3db9dc871d7b187e30bfd3297eea2557e9be99897ea8ff7a29a21", + "8110cf482f66dc37125e619d73075af932521724ffc7108309e88f361efe8c8a", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPe98QUPieXy5KFPVjuZNpcC9JY7K7buJEm8nWvJogK4kTda7eLjK9U4PnMNbSjEkpjDJazeBZ4rhYNYD7N6GEdaysj1AYSb5", + "xpub": "tpubD6NzVbkrYhZ4XcACN3PEwNjRpR1g4tZjBVk5pdMR2B6dbd3HYhdGVZNKofAiFZd9okBserZvv58A6tBX4pE64UpXGNTSesfUW7PpW36HuKz", + "pubs": [ + "f95886b02a84928c5c15bdca32784993105f73de27fa6ad8c1a60389b999267c", + "71522134160685eb779857033bfc84c7626f13556154653a51dd42619064e679", + "48957b4158b2c5c3f4c000f51fd2cf0fd5ff8868ebfb194256f5e9131fc74bd8", + "086dda8139b3a84944010648d2b674b70447be3ae59322c09a4907bc80be62c1", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPe3ZJmcj9aJ2EPZJYYCh6Lp3v82p75wspgaXmtDZ2RBtkAtWcGnW2VQDzMHQPBkCKMoYTqh1RfJKjv4PcmWVR7KqTpjsdboN", + "xpub": "tpubD6NzVbkrYhZ4XWb6fGPjyhgLxapUhXszv7ehQYrQWDgDX4nYWcNcbgWcM2RhYo9s2mbZcfZJ8t5LzYcr24FK79zVybsw5Qj3Rtqug8jpJMy", + "pubs": [ + "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", + "8a104c54cd34acba60c97dd8f1f7abc89ba9587afd88dc928e91aca7b1c50d20", + "13ba6b252a4eb5ef31d39cb521724cdab19a698323f5c17093f28fb1821d052f", + "f6c2b4863fd5ba1ba09e3a890caed8b75ffbe013ebab31a06ab87cd6f72506af", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPdKziibn63Rm6aNzp7dSjDnufZMStXr71Huz7iihCRpbZZZ6Voy5HyuHCWx6foHMipzMzUq4tZrtkZ24DJwz5EeNWdsuwX5h", + "xpub": "tpubD6NzVbkrYhZ4Wo2WcFSgSqRD9QWkGxddo6WSqsVBx7uQ8QEtM7WncKDRjhFEexK119NigyCsFygA4b7sAPQxqebyFGAZ9XVV1BtcgNzbCRR", + "pubs": [ + "03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb", + "bbf56b14b119bccafb686adec2e3d2a6b51b1626213590c3afa815d1fd36f85d", + "2994519e31bbc238a07d82f85c9832b831705d2ee4a2dbb477ecec8a3f570fe5", + "68991b5c139a4c479f8c89d6254d288c533aefc0c5b91fac6c89019c4de64988", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPen4PGtDwURYnCtVMDejyE8vVwMGhQWfVqB2FBPdekhTacDW4vmsKTsgC1wsncVqXiZdX2YFGAnKoLXYf42M78fQJFzuDYFN", + "xpub": "tpubD6NzVbkrYhZ4YF6BAXtXsqCtmv1HNyvsoSXHDsJzpnTtffH1onTEwC5SnLzCHPKPebh2i7Gxvi9kJNADcpuSmH8oM3rCYcHVtdXHjpYoKnX", + "pubs": [ + "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247", + "c8558b7caf198e892032d91f1a48ee9bdc25462b83b4d0ac62bb7fb2a0df630e", + "8a4bcaba0e970685858d133a4d0079c8b55bbc755599e212285691eb779ce3dc", + "b0d68ada13e0d954b3921b88160d4453e9c151131c2b7c724e08f538a666ceb3", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPd91vCgRmbzA13wyip2RimYeVEkAyZvsEN5pUSB3T43SEBxPsytkxb42d64W2EiRE9CewpJQkzR8HKHLV8Uhk4dMF5yRPaTv", + "xpub": "tpubD6NzVbkrYhZ4Wc3i6L6N1Pp7cyVeyMcdLrFGXGDGzCfdCa5F4Zs3EY46N72Ws8QDEUYBVwXfDfda2UKSseSdU1fsBegJBhGCZyxkf28bkQ6", + "pubs": [ + "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744", + "8e971b781b7ce7ab742d80278f2dfe7dd330f3efd6d00047f4a2071f2e7553cb", + "b811d66739b9f07435ccda907ec5cd225355321c35e0a7c7791232f24cf10632", + "4cd27a5552c272bc80ba544e9cc6340bb906969f5e7a1510b6cef9592683fbc9", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPdEhLRxxwzTv2t18j7ruoffPeqAwVA2qXJ2P66RaMZLUWQ85SjoA7xPxdSgCB9UZ72m65qbnaLPtFTfHVP3MEmkpZk1Bv8RT", + "xpub": "tpubD6NzVbkrYhZ4Whj8KcdYPsa9T2efHC6iExzS7gynaJdv8WdripPwjq6NaH5gQJGrLmvUwHY1smhiakUosXNDTEa6qfKUQdLKV6DJBre6XvQ", + "pubs": [ + "d0c19def28bb1b39451c1a814737615983967780d223b79969ba692182c6006b", + "cb1d1b1dc62fec1894d4c3d9a1b6738e5ff9c273a64f74e9ab363095f45e9c47", + "245be588f41acfaeb9481aa132717db56ee1e23eb289729fe2b8bde8f9a00830", + "5bc4ad6d6187fa82728c85a073b428483295288f8aef5722e47305b5872f7169", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPcxbqxzcMAwQpiCD8x6qaZEJTxdKxw4w9GuMzDACTD9yhEsHGfqQcfYX4LivosLDDngTykYEp9JnTdcqY7cHqU8PpeFFKyV3", + "xpub": "tpubD6NzVbkrYhZ4WRddreGwaM4wHDj57S2V8XuFF9NGMLjY7PckqZ23PebZR1wGA4w84uX2vZphdZVsnREjij1ibYjEBTaTVQCEZCLs4xUDapx", + "pubs": [ + "065cc1b92bd99e5a3e626e8296a366b2d132688eb43aea19bc14fd8f43bf07fb", + "5b95633a7dda34578b6985e6bfd85d83ec38b7ded892a9b74a3d899c85890562", + "dc86d434b9a34495c8e845b969d51f80d19a8df03b400353ffe8036a0c22eb60", + "06c8ffde238745b29ae8a97ae533e1f3edf214bba6ec58b5e7b9451d1d61ec19", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPe6zLoU8MTTXgsdJVNBErrYGpoGwHf5VGvwUzdNc7NHeCSzkJkniCxBhZWujXjmD4HZmBBrnr3URgJjM6GxRgMmEhLdqNTWG", + "xpub": "tpubD6NzVbkrYhZ4Xa28h7nwrsBoSepRXWRmRqsc5nyb5MHfmRjmFmRhYnG4d9dC7uxixN5AfsEv1Lz3mCAuWvERyvPgKozHUVjfo8EG6foJGy7", + "pubs": [ + "d826a0a53abb6ffc60df25b9c152870578faef4b2eb5a09bdd672bbe32cdd79b", + "939365e0359ff6bc6f6404ee220714c5d4a0d1e36838b9e2081ede217674e2ba", + "4e8767edcf7d3d90258cfbbea01b784f4d2de813c4277b51279cf808bac410a2", + "d42a2c280940bfc6ede971ae72cde2e1df96c6da7dab06a132900c6751ade208", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPeB5o5oCsN2dVxM2mtJiYERQEBRc4JNwC1DFGYaEdNkmh8jJYVPU76YhkFoRoWTdh1p3yQGykG8TfDW34dKgrgSx28gswUyL", + "xpub": "tpubD6NzVbkrYhZ4Xe7aySsTmSHcXNYi3duSoj11TweMiejaqhW3Ay4DZFPZJses4sfpk4b9VHRhn8v4cKTMjugMM3hqXcqSSmRdiW8QvASXjfY", + "pubs": [ + "e360564b2e0e8d06681b6336a29d0750210e8f34afd9afb5e6fd5fe6dba26c81", + "76b4900f00a1dcce463b6d8e02b768518fce4f9ecd6679a13ad78ea1e4815ad3", + "5575556e263c8ed52e99ab02147cc05a738869afe0039911b5a60a780f4e43d2", + "593b00e2c8d4bd6dda0fd9e238888acf427bb4e128887fd5a40e0e9da78cbc01", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPfEH6jHemkGDjZRnAaKFJVGH8pQU638E6SdbX9hxit1tK2sfFPfL6KS7v8FfUKxstbfEpzSymbdfBM9Y5UkrxErF9fJaKLK3", + "xpub": "tpubD6NzVbkrYhZ4YhJtcwKN9fsr8TJ6jeSD4Zsv6vWPTQ2VH7rHn6nK4WWBCzKK7FkdVVwm3iztCU1UmStY4hX6gRbBmp9UzK9C59dQEzeXS12", + "pubs": [ + "7631cacec3343052d87ef4d0065f61dde82d7d2db0c1cc02ef61ef3c982ea763", + "c05e44a9e735d1b1bef62e2c0d886e6fb4923b2649b67828290f5cacc51c71b7", + "b33198b20701afe933226c92fd0e3d51d3f266f1113d864dbd026ae3166ef7f2", + "f99643ac3f4072ee4a949301e86963a9ca0ad57f2ef29f6b84fda037d7cac85b", + ] + }, + { + "xprv": "tprv8ZgxMBicQKsPdNWU38dT6aGxtqJR4oYS5kPpLVBcuKiiu7gqTYqMMqhUG6DP7pPahzPQu36sWSmeLCP1C4AwqcR5FX2RyRoZfd4B8pAnSdX", + "xpub": "tpubD6NzVbkrYhZ4WqYFvnJ3Vyw5TrpME8jLf3zbd1DvKbX7jbwc5wewYLKLSFRzZWV6hZj7XhsXAy7fhE5jB25DiWyNM3ztXbsXHRVCrp5BiPY", + "pubs": [ + "2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7", + "83df59d0a5c951cdd62b7ab225a62079f48d2a333a86e66c35420d101446e92e", + "2a654bf234d819055312f9ca03fad5836f9163b09cdd24d29678f694842b874a", + "aa0334ab910047387c912a21ec0dab806a47ffa38365060dbc5d47c18c6e66e7", + ] + }, + { + "xprv": "tprv8mGPkMVz5mZuJDnC2NjjAv7E9Zqa5LCgX4zawbZu5nzTtLb5kGhPwycX4H1gtW1f5ZdTKTNtQJ61hk71F2TdcQ93EFDTpUcPBr98QRji615", + "xpub": "tpubDHxRtmYEE9FaBgoyv2QKaKmLibMWEfPb6NbNE7cCW4nripqrNfWz8UEPEPbHCrakwLvwFfsqoaf4pjX4gWStp4nECRf1QwBKPkLqnY8pHbj", + "pubs": [ + "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3", + "b2749b74d51a78f5fe3ebb3a7c0ff266a468cade143dfa265c57e325177edf00", + "6b8747a6bbe4440d7386658476da51f6e49a220508a7ec77fe7bccc3e7baa916", + "4674bf4d9ebbe01bf0aceaca2472f63198655ecf2df810f8d69b38421972318e", + ] + } +] + +CHANGE_XPRV = "tprv8ZgxMBicQKsPcyDrWwiecVnTtFmfRwbfFqEfR4ZGWvq5aTTwLBWmAm5zrbMcYtb9gQNFfhRfqhhrBG37U3nhmXxEgeEPBJGHAPrHCrAd1WX" +CHANGE_XPUB = "tpubD6NzVbkrYhZ4WSFeQbPF1uSaTHHbbGnZq8qShabZwCdUQwihxaLMMFhs2kidGF2qrRKiQVqw8VoyuTHj1bZqmMXMeciaU1gBjWA1sim2zUB" + +# Point with no known discrete log. +H_POINT = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0" + + +def key(hex_key): + """Construct an x-only pubkey from its hex representation.""" + return bytes.fromhex(hex_key) + +def pk(hex_key): + """Construct a script expression for taproot_construct for pk(hex_key).""" + return (None, CScript([bytes.fromhex(hex_key), OP_CHECKSIG])) + +def compute_taproot_address(pubkey, scripts): + """Compute the address for a taproot output with given inner key and scripts.""" + tap = taproot_construct(pubkey, scripts) + assert tap.scriptPubKey[0] == 0x51 + assert tap.scriptPubKey[1] == 0x20 + return encode_segwit_address("bcrt", 1, tap.scriptPubKey[2:]) + +class WalletTaprootTest(BitcoinTestFramework): + """Test generation and spending of P2TR address outputs.""" + + def set_test_params(self): + self.num_nodes = 2 + self.setup_clean_chain = True + self.extra_args = [['-keypool=100'], ['-keypool=100']] + self.supports_cli = False + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + self.skip_if_no_sqlite() + + def setup_network(self): + self.setup_nodes() + + def init_wallet(self, i): + pass + + @staticmethod + def rand_keys(n): + ret = [] + idxes = set() + for _ in range(n): + while True: + i = random.randrange(len(KEYS)) + if not i in idxes: + break + idxes.add(i) + ret.append(KEYS[i]) + return ret + + @staticmethod + def make_desc(pattern, privmap, keys, pub_only = False): + pat = pattern.replace("$H", H_POINT) + for i in range(len(privmap)): + if privmap[i] and not pub_only: + pat = pat.replace("$%i" % (i + 1), keys[i]['xprv']) + else: + pat = pat.replace("$%i" % (i + 1), keys[i]['xpub']) + return descsum_create(pat) + + @staticmethod + def make_addr(treefn, keys, i): + args = [] + for j in range(len(keys)): + args.append(keys[j]['pubs'][i]) + return compute_taproot_address(*treefn(*args)) + + def do_test_addr(self, comment, pattern, privmap, treefn, keys): + self.log.info("Testing %s address derivation" % comment) + desc = self.make_desc(pattern, privmap, keys, False) + desc_pub = self.make_desc(pattern, privmap, keys, True) + assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub) + result = self.addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}]) + assert(result[0]['success']) + for i in range(4): + addr_g = self.addr_gen.getnewaddress(address_type='bech32') + if treefn is not None: + addr_r = self.make_addr(treefn, keys, i) + assert_equal(addr_g, addr_r) + + def do_test(self, comment, pattern, privmap, treefn, nkeys): + keys = self.rand_keys(nkeys) + self.do_test_addr(comment, pattern, privmap, treefn, keys) + + def run_test(self): + self.log.info("Creating wallets...") + self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True) + self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen") + + self.do_test( + "tr(XPRV)", + "tr($1/*)", + [True], + lambda k1: (key(k1), []), + 1 + ) + self.do_test( + "tr(H,XPRV)", + "tr($H,pk($1/*))", + [True], + lambda k1: (key(H_POINT), [pk(k1)]), + 1 + ) + self.do_test( + "tr(XPRV,{H,{H,XPUB}})", + "tr($1/*,{pk($H),{pk($H),pk($2/*)}})", + [True, False], + lambda k1, k2: (key(k1), [pk(H_POINT), [pk(H_POINT), pk(k2)]]), + 2 + ) + self.do_test( + "tr(XPUB,{{H,{H,XPUB}},{H,{H,{H,XPRV}}}})", + "tr($1/*,{{pk($H),{pk($H),pk($2/*)}},{pk($H),{pk($H),{pk($H),pk($3/*)}}}})", + [False, False, True], + lambda k1, k2, k3: (key(k1), [[pk(H_POINT), [pk(H_POINT), pk(k2)]], [pk(H_POINT), [pk(H_POINT), [pk(H_POINT), pk(k3)]]]]), + 3 + ) + +if __name__ == '__main__': + WalletTaprootTest().main() diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index fbc0f995d2..e7dd7592b6 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -17,6 +17,7 @@ import struct from io import BytesIO +from test_framework.blocktools import COINBASE_MATURITY from test_framework.bdb import dump_bdb_kv from test_framework.messages import deser_compact_size, deser_string from test_framework.test_framework import BitcoinTestFramework @@ -118,11 +119,11 @@ class UpgradeWalletTest(BitcoinTestFramework): assert_equal(wallet.getwalletinfo()["walletversion"], previous_version) def run_test(self): - self.nodes[0].generatetoaddress(101, self.nodes[0].getnewaddress()) + self.nodes[0].generatetoaddress(COINBASE_MATURITY + 1, self.nodes[0].getnewaddress()) self.dumb_sync_blocks() # # Sanity check the test framework: res = self.nodes[0].getblockchaininfo() - assert_equal(res['blocks'], 101) + assert_equal(res['blocks'], COINBASE_MATURITY + 1) node_master = self.nodes[0] v16_3_node = self.nodes[1] v15_2_node = self.nodes[2] @@ -130,7 +131,7 @@ class UpgradeWalletTest(BitcoinTestFramework): # Send coins to old wallets for later conversion checks. v16_3_wallet = v16_3_node.get_wallet_rpc('wallet.dat') v16_3_address = v16_3_wallet.getnewaddress() - node_master.generatetoaddress(101, v16_3_address) + node_master.generatetoaddress(COINBASE_MATURITY + 1, v16_3_address) self.dumb_sync_blocks() v16_3_balance = v16_3_wallet.getbalance() diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py index c345c382d0..6743c4a49b 100755 --- a/test/functional/wallet_watchonly.py +++ b/test/functional/wallet_watchonly.py @@ -5,6 +5,7 @@ """Test createwallet watchonly arguments. """ +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -36,7 +37,7 @@ class CreateWalletWatchonlyTest(BitcoinTestFramework): wo_wallet.importpubkey(pubkey=def_wallet.getaddressinfo(wo_change)['pubkey']) # generate some btc for testing - node.generatetoaddress(101, a1) + node.generatetoaddress(COINBASE_MATURITY + 1, a1) # send 1 btc to our watch-only address txid = def_wallet.sendtoaddress(wo_addr, 1) diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index f6e46ac4bb..f8f24bb1ff 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -24,6 +24,10 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "wallet/fees -> wallet/wallet -> wallet/fees" "wallet/wallet -> wallet/walletdb -> wallet/wallet" "node/coinstats -> validation -> node/coinstats" + # Temporary circular dependencies that allow wallet.h/wallet.cpp to be + # split up in a MOVEONLY commit. These are removed in #21206. + "wallet/receive -> wallet/wallet -> wallet/receive" + "wallet/spend -> wallet/wallet -> wallet/spend" ) EXIT_CODE=0 diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt index 78ffe4def3..267c06ea20 100644 --- a/test/lint/lint-spelling.ignore-words.txt +++ b/test/lint/lint-spelling.ignore-words.txt @@ -6,6 +6,7 @@ fpr hights hist inout +invokable mor nin ser diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 4f6f92bd3c..2850cfcea5 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -98,7 +98,6 @@ implicit-unsigned-integer-truncation:crypto/ implicit-unsigned-integer-truncation:leveldb/ # std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9 implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage -shift-base:nanobench.h shift-base:*/include/c++/ shift-base:arith_uint256.cpp shift-base:crypto/ |