mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-22 16:14:50 +01:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef70f9b52b | ||
|
|
c6e4a1fca5 | ||
|
|
89a9a9d938 | ||
|
|
abae8aeff1 | ||
|
|
8b8b3a9a5f | ||
|
|
dcb032dcdf | ||
|
|
6042dfe008 | ||
|
|
75b5d8c4ea | ||
|
|
7a590d8390 | ||
|
|
5d12143c73 | ||
|
|
7bee41452b | ||
|
|
ff56bb9b44 | ||
|
|
db445d4e5a | ||
|
|
ad94165db9 | ||
|
|
39ece4fc28 | ||
|
|
70ee1f8709 | ||
|
|
a9eab081d5 | ||
|
|
cfdd6b2f6c | ||
|
|
a3fe125490 | ||
|
|
3362a95be3 | ||
|
|
924cf794e1 | ||
|
|
252844329f | ||
|
|
67225e2fd7 | ||
|
|
2a5cc40dc4 | ||
|
|
53dcf2b407 | ||
|
|
d8bc0ce1da | ||
|
|
f9db08e8ca | ||
|
|
79358817e5 | ||
|
|
9666dbaf09 | ||
|
|
b90157891a | ||
|
|
6f04264bbb | ||
|
|
5782fdcd8c | ||
|
|
de5e48a461 | ||
|
|
df5131bd41 | ||
|
|
9f556622c5 | ||
|
|
542651cfb4 | ||
|
|
ec71f06a8d | ||
|
|
7edebedef1 | ||
|
|
fb9ad043f8 | ||
|
|
91fa15aaeb | ||
|
|
96f15e8bb3 | ||
|
|
60f7a97930 | ||
|
|
2f9fd29321 | ||
|
|
5331ad0506 | ||
|
|
94065024c7 | ||
|
|
85aacc41ba | ||
|
|
bb90695551 | ||
|
|
5150accdd2 | ||
|
|
1e49fe450d | ||
|
|
b0e88b8914 | ||
|
|
0242b5afa4 | ||
|
|
9e87d82e7f | ||
|
|
76dd5257f9 | ||
|
|
f046d846ae | ||
|
|
1476554d3b | ||
|
|
f13041f17b | ||
|
|
f9fc08c5f8 | ||
|
|
dc4923a71b | ||
|
|
248e5ec348 | ||
|
|
eb2cc84a31 | ||
|
|
9461f98c53 | ||
|
|
703a24418c | ||
|
|
5f51fd6d59 | ||
|
|
29899ecd36 | ||
|
|
f7adb32e38 | ||
|
|
86fadee990 | ||
|
|
8bc1badada | ||
|
|
24d796a6cc | ||
|
|
168efeaca6 | ||
|
|
73e538cf6a | ||
|
|
96dc936862 | ||
|
|
7ff32a6b98 | ||
|
|
b72fbabe17 | ||
|
|
06544faff0 | ||
|
|
1b5af2c177 | ||
|
|
f7dbcaa72f | ||
|
|
89306ab0df | ||
|
|
5b47b8efd4 | ||
|
|
e1ed37edae | ||
|
|
786825c719 | ||
|
|
480d6bb078 | ||
|
|
c64128df58 | ||
|
|
0d49c82edd | ||
|
|
833180f538 | ||
|
|
fcefc6851a | ||
|
|
fcdea8ad2a | ||
|
|
465a583f9d | ||
|
|
eece974d0a | ||
|
|
0f681cecad | ||
|
|
eb202ea21d | ||
|
|
83aafd5b32 | ||
|
|
6ba1f15432 | ||
|
|
6bfee8a8c2 | ||
|
|
2936dbc557 | ||
|
|
2307a6eb2b | ||
|
|
5f71eac634 | ||
|
|
cf3d7f94c2 | ||
|
|
fab0fbefcf | ||
|
|
b5ec6d4bf8 | ||
|
|
3e4829af09 | ||
|
|
9833545d18 | ||
|
|
82e2b9cb25 | ||
|
|
65e7a8b97f | ||
|
|
c6d905746b | ||
|
|
1ffd67f11f | ||
|
|
48c845902a | ||
|
|
3d827bee69 | ||
|
|
4a2960f73e | ||
|
|
0333914467 | ||
|
|
8935869487 | ||
|
|
dbaadc9ea9 | ||
|
|
ad6d845ac9 | ||
|
|
517010e30e | ||
|
|
8c4cd2bd89 | ||
|
|
ff41e479a0 | ||
|
|
f0f745d8de | ||
|
|
cd2f4f35bb |
@@ -1,4 +1,3 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
os: linux
|
||||
language: minimal
|
||||
@@ -143,12 +142,11 @@ jobs:
|
||||
BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror"
|
||||
- stage: lint
|
||||
env:
|
||||
sudo: false
|
||||
cache: false
|
||||
language: python
|
||||
python: '3.6'
|
||||
install:
|
||||
- travis_retry pip install flake8
|
||||
- travis_retry pip install flake8==3.5.0
|
||||
before_script:
|
||||
- git fetch --unshallow
|
||||
script:
|
||||
|
||||
@@ -19,6 +19,7 @@ endif
|
||||
BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT)
|
||||
BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT)
|
||||
BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT)
|
||||
BITCOIN_TX_BIN=$(top_builddir)/src/$(BITCOIN_TX_NAME)$(EXEEXT)
|
||||
BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)
|
||||
|
||||
empty :=
|
||||
@@ -74,6 +75,7 @@ $(BITCOIN_WIN_INSTALLER): all-recursive
|
||||
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release
|
||||
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $(top_builddir)/release
|
||||
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release
|
||||
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_TX_BIN) $(top_builddir)/release
|
||||
@test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \
|
||||
echo error: could not build $@
|
||||
@echo built $@
|
||||
@@ -167,6 +169,9 @@ $(BITCOIND_BIN): FORCE
|
||||
$(BITCOIN_CLI_BIN): FORCE
|
||||
$(MAKE) -C src $(@F)
|
||||
|
||||
$(BITCOIN_TX_BIN): FORCE
|
||||
$(MAKE) -C src $(@F)
|
||||
|
||||
if USE_LCOV
|
||||
LCOV_FILTER_PATTERN=-p "/usr/include/" -p "src/leveldb/" -p "src/bench/" -p "src/univalue" -p "src/crypto/ctaes" -p "src/secp256k1"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||
AC_PREREQ([2.60])
|
||||
define(_CLIENT_VERSION_MAJOR, 0)
|
||||
define(_CLIENT_VERSION_MINOR, 16)
|
||||
define(_CLIENT_VERSION_REVISION, 99)
|
||||
define(_CLIENT_VERSION_MINOR, 17)
|
||||
define(_CLIENT_VERSION_REVISION, 1)
|
||||
define(_CLIENT_VERSION_BUILD, 0)
|
||||
define(_CLIENT_VERSION_IS_RELEASE, false)
|
||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||
define(_COPYRIGHT_YEAR, 2018)
|
||||
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
||||
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
|
||||
|
||||
@@ -13,7 +13,7 @@ package_name_ns = sys.argv[2]
|
||||
ds = DSStore.open(output_file, 'w+')
|
||||
ds['.']['bwsp'] = {
|
||||
'ShowStatusBar': False,
|
||||
'WindowBounds': b'{{300, 280}, {500, 343}}',
|
||||
'WindowBounds': '{{300, 280}, {500, 343}}',
|
||||
'ContainerShowSidebar': False,
|
||||
'SidebarWidth': 0,
|
||||
'ShowTabView': False,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
build_darwin_CC: = $(shell xcrun -f clang)
|
||||
build_darwin_CXX: = $(shell xcrun -f clang++)
|
||||
build_darwin_AR: = $(shell xcrun -f ar)
|
||||
build_darwin_RANLIB: = $(shell xcrun -f ranlib)
|
||||
build_darwin_STRIP: = $(shell xcrun -f strip)
|
||||
build_darwin_OTOOL: = $(shell xcrun -f otool)
|
||||
build_darwin_NM: = $(shell xcrun -f nm)
|
||||
build_darwin_CC:=$(shell xcrun -f clang)
|
||||
build_darwin_CXX:=$(shell xcrun -f clang++)
|
||||
build_darwin_AR:=$(shell xcrun -f ar)
|
||||
build_darwin_RANLIB:=$(shell xcrun -f ranlib)
|
||||
build_darwin_STRIP:=$(shell xcrun -f strip)
|
||||
build_darwin_OTOOL:=$(shell xcrun -f otool)
|
||||
build_darwin_NM:=$(shell xcrun -f nm)
|
||||
build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool)
|
||||
build_darwin_SHA256SUM = shasum -a 256
|
||||
build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o
|
||||
build_darwin_SHA256SUM=shasum -a 256
|
||||
build_darwin_DOWNLOAD=curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o
|
||||
|
||||
#darwin host on darwin builder. overrides darwin host preferences.
|
||||
darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION)
|
||||
|
||||
@@ -8,7 +8,7 @@ $(package)_dependencies=openssl zlib
|
||||
$(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext
|
||||
$(package)_build_subdir=qtbase
|
||||
$(package)_qt_libs=corelib network widgets gui plugins testlib
|
||||
$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch
|
||||
$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch xkb-default.patch
|
||||
|
||||
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
|
||||
$(package)_qttranslations_sha256_hash=9822084f8e2d2939ba39f4af4c0c2320e45d5996762a9423f833055607604ed8
|
||||
@@ -83,7 +83,7 @@ $(package)_config_opts_darwin += -device-option MAC_TARGET=$(host)
|
||||
$(package)_config_opts_darwin += -device-option MAC_LD64_VERSION=$(LD64_VERSION)
|
||||
endif
|
||||
|
||||
$(package)_config_opts_linux = -qt-xkbcommon
|
||||
$(package)_config_opts_linux = -qt-xkbcommon-x11
|
||||
$(package)_config_opts_linux += -qt-xcb
|
||||
$(package)_config_opts_linux += -system-freetype
|
||||
$(package)_config_opts_linux += -no-feature-sessionmanager
|
||||
@@ -119,6 +119,7 @@ define $(package)_extract_cmds
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
sed -i.old "s|FT_Get_Font_Format|FT_Get_X11_Font_Format|" qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp && \
|
||||
sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \
|
||||
sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \
|
||||
sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \
|
||||
@@ -136,6 +137,7 @@ define $(package)_preprocess_cmds
|
||||
patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch &&\
|
||||
patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch &&\
|
||||
patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch &&\
|
||||
patch -p1 -i $($(package)_patch_dir)/xkb-default.patch &&\
|
||||
echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
|
||||
echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
|
||||
echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
|
||||
|
||||
26
depends/patches/qt/xkb-default.patch
Normal file
26
depends/patches/qt/xkb-default.patch
Normal file
@@ -0,0 +1,26 @@
|
||||
--- old/qtbase/src/gui/configure.pri 2018-06-06 17:28:10.000000000 -0400
|
||||
+++ new/qtbase/src/gui/configure.pri 2018-08-17 18:43:01.589384567 -0400
|
||||
@@ -43,18 +43,11 @@
|
||||
}
|
||||
|
||||
defineTest(qtConfTest_xkbConfigRoot) {
|
||||
- qtConfTest_getPkgConfigVariable($${1}): return(true)
|
||||
-
|
||||
- for (dir, $$list("/usr/share/X11/xkb", "/usr/local/share/X11/xkb")) {
|
||||
- exists($$dir) {
|
||||
- $${1}.value = $$dir
|
||||
- export($${1}.value)
|
||||
- $${1}.cache += value
|
||||
- export($${1}.cache)
|
||||
- return(true)
|
||||
- }
|
||||
- }
|
||||
- return(false)
|
||||
+ $${1}.value = "/usr/share/X11/xkb"
|
||||
+ export($${1}.value)
|
||||
+ $${1}.cache += value
|
||||
+ export($${1}.cache)
|
||||
+ return(true)
|
||||
}
|
||||
|
||||
defineTest(qtConfTest_qpaDefaultPlatform) {
|
||||
@@ -279,6 +279,7 @@ To build executables for ARM:
|
||||
cd depends
|
||||
make HOST=arm-linux-gnueabihf NO_QT=1
|
||||
cd ..
|
||||
./autogen.sh
|
||||
./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++
|
||||
make
|
||||
|
||||
|
||||
133
doc/descriptors.md
Normal file
133
doc/descriptors.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Support for Output Descriptors in Bitcoin Core
|
||||
|
||||
Since Bitcoin Core v0.17, there is support for Output Descriptors in the
|
||||
`scantxoutset` RPC call. This is a simple language which can be used to
|
||||
describe collections of output scripts.
|
||||
|
||||
This document describes the language. For the specifics on usage for scanning
|
||||
the UTXO set, see the `scantxoutset` RPC help.
|
||||
|
||||
## Features
|
||||
|
||||
Output descriptors currently support:
|
||||
- Pay-to-pubkey scripts (P2PK), through the `pk` function.
|
||||
- Pay-to-pubkey-hash scripts (P2PKH), through the `pkh` function.
|
||||
- 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.
|
||||
- Multisig scripts, through the `multi` function.
|
||||
- Any type of supported address through the `addr` function.
|
||||
- Raw hex scripts through the `raw` function.
|
||||
- Public keys (compressed and uncompressed) in hex notation, or BIP32 extended pubkeys with derivation paths.
|
||||
|
||||
## Examples
|
||||
|
||||
- `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` describes a P2PK output with the specified public key.
|
||||
- `pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)` describes a P2PKH output with the specified public key.
|
||||
- `wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)` describes a P2WPKH output with the specified public key.
|
||||
- `sh(wpkh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))` describes a P2SH-P2WPKH output with the specified public key.
|
||||
- `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` describes any P2PK, P2PKH, P2WPKH, or P2SH-P2WPKH output with the specified public key.
|
||||
- `sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)))` describes an (overly complicated) P2SH-P2WSH-P2PKH output with the specified public key.
|
||||
- `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` describes a bare *1-of-2* multisig output with keys in the specified order.
|
||||
- `sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))` describes a P2SH *2-of-2* multisig output with keys in the specified order.
|
||||
- `wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))` describes a P2WSH *2-of-3* multisig output with keys in the specified order.
|
||||
- `sh(wsh(multi(1,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e)))` describes a P2SH-P2WSH *1-of-3* multisig output with keys in the specified order.
|
||||
- `pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8)` describes a P2PK output with the public key of the specified xpub.
|
||||
- `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)` describes a P2PKH output with child key *1'/2* of the specified xpub.
|
||||
- `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).
|
||||
|
||||
## Reference
|
||||
|
||||
Descriptors consist of several types of expressions. The top level expression is always a `SCRIPT`.
|
||||
|
||||
`SCRIPT` expressions:
|
||||
- `sh(SCRIPT)` (top level only): P2SH embed the argument.
|
||||
- `wsh(SCRIPT)` (not inside another 'wsh'): 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.
|
||||
- `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.
|
||||
- `addr(ADDR)` (top level only): the script which ADDR expands to.
|
||||
- `raw(HEX)` (top level only): the script whose hex encoding is HEX.
|
||||
|
||||
`KEY` expressions:
|
||||
- Hex encoded public keys (66 characters starting with `02` or `03`, or 130 characters starting with `04`).
|
||||
- Inside `wpkh` and `wsh`, only compressed public keys are permitted.
|
||||
- [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 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.
|
||||
- Instead of a `'`, the suffix `h` can be used to denote hardened derivation.
|
||||
|
||||
`ADDR` expressions are any type of supported address:
|
||||
- P2PKH addresses (base58, of the form `1...`). Note that P2PKH addresses in descriptors cannot be used for P2PK outputs (use the `pk` function instead).
|
||||
- P2SH addresses (base58, of the form `3...`, defined in [BIP 13](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki)).
|
||||
- Segwit addresses (bech32, of the form `bc1...`, defined in [BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)).
|
||||
|
||||
## Explanation
|
||||
|
||||
### Single-key scripts
|
||||
|
||||
Many single-key constructions are used in practice, generally including
|
||||
P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH. Many more combinations are
|
||||
imaginable, though they may not be optimal: P2SH-P2PK, P2SH-P2PKH,
|
||||
P2WSH-P2PK, P2WSH-P2PKH, P2SH-P2WSH-P2PK, P2SH-P2WSH-P2PKH.
|
||||
|
||||
To describe these, we model these as functions. The functions `pk`
|
||||
(P2PK), `pkh` (P2PKH) and `wpkh` (P2WPKH) take as input a public key in
|
||||
hexadecimal notation (which will be extended later), and return the
|
||||
corresponding *scriptPubKey*. The functions `sh` (P2SH) and `wsh` (P2WSH)
|
||||
take as input a script, and return the script describing P2SH and P2WSH
|
||||
outputs with the input as embedded script. The names of the functions do
|
||||
not contain "p2" for brevity.
|
||||
|
||||
### Multisig
|
||||
|
||||
Several pieces of software use multi-signature (multisig) scripts based
|
||||
on Bitcoin's OP_CHECKMULTISIG opcode. To support these, we introduce the
|
||||
`multi(k,key_1,key_2,...,key_n)` function. It represents a *k-of-n*
|
||||
multisig policy, where any *k* out of the *n* provided public keys must
|
||||
sign.
|
||||
|
||||
Key order is significant. A `multi()` expression describes a multisig script
|
||||
with keys in the specified order, and in a search for TXOs, it will not match
|
||||
outputs with multisig scriptPubKeys that have the same keys in a different
|
||||
order. Also, to prevent a combinatorial explosion of the search space, if more
|
||||
than one of the `multi()` key arguments is a BIP32 wildcard path ending in `/*`
|
||||
or `*'`, the `multi()` expression only matches multisig scripts with the `i`th
|
||||
child key from each wildcard path in lockstep, rather than scripts with any
|
||||
combination of child keys from each wildcard path.
|
||||
|
||||
### BIP32 derived keys and chains
|
||||
|
||||
Most modern wallet software and hardware uses keys that are derived using
|
||||
BIP32 ("HD keys"). We support these directly by permitting strings
|
||||
consisting of an extended public key (commonly referred to as an *xpub*)
|
||||
plus derivation path anywhere a public key is expected. The derivation
|
||||
path consists of a sequence of 0 or more integers (in the range
|
||||
*0..2<sup>31</sup>-1*) each optionally followed by `'` or `h`, and
|
||||
separated by `/` characters. The string may optionally end with the
|
||||
literal `/*` or `/*'` (or `/*h`) to refer to all unhardened or hardened
|
||||
child keys in a configurable range (by default `0-1000`, inclusive).
|
||||
|
||||
Whenever a public key is described using a hardened derivation step, the
|
||||
script cannot be computed without access to the corresponding private
|
||||
key.
|
||||
|
||||
### Including private keys
|
||||
|
||||
Often it is useful to communicate a description of scripts along with the
|
||||
necessary private keys. For this reason, anywhere a public key or xpub is
|
||||
supported, a private key in WIF format or xprv may be provided instead.
|
||||
This is useful when private keys are necessary for hardened derivation
|
||||
steps, or for dumping wallet descriptors including private key material.
|
||||
|
||||
### Compatibility with old wallets
|
||||
|
||||
In order to easily represent the sets of scripts currently supported by
|
||||
existing Bitcoin Core wallets, a convenience function `combo` is
|
||||
provided, which takes as input a public key, and describes a set of P2PK,
|
||||
P2PKH, P2WPKH, and P2SH-P2WPH scripts for that key. In case the key is
|
||||
uncompressed, the set only includes P2PK and P2PKH scripts.
|
||||
@@ -1,17 +1,21 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
|
||||
.TH BITCOIN-CLI "1" "July 2018" "bitcoin-cli v0.16.99.0" "User Commands"
|
||||
.TH BITCOIN-CLI "1" "December 2018" "bitcoin-cli v0.17.1.0" "User Commands"
|
||||
.SH NAME
|
||||
bitcoin-cli \- manual page for bitcoin-cli v0.16.99.0
|
||||
bitcoin-cli \- manual page for bitcoin-cli v0.17.1.0
|
||||
.SH SYNOPSIS
|
||||
.B bitcoin-cli
|
||||
[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR] \fI\,Send command to Bitcoin Core\/\fR
|
||||
.br
|
||||
.B bitcoin-cli
|
||||
[\fI\,options\/\fR] \fI\,-named <command> \/\fR[\fI\,name=value\/\fR]... \fI\,Send command to Bitcoin Core (with named arguments)\/\fR
|
||||
.br
|
||||
.B bitcoin-cli
|
||||
[\fI\,options\/\fR] \fI\,help List commands\/\fR
|
||||
.br
|
||||
.B bitcoin-cli
|
||||
[\fI\,options\/\fR] \fI\,help <command> Get help for a command\/\fR
|
||||
.SH DESCRIPTION
|
||||
Bitcoin Core RPC client version v0.16.99.0
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
bitcoin\-cli [options] <command> [params]
|
||||
Send command to Bitcoin Core
|
||||
.IP
|
||||
bitcoin\-cli [options] \fB\-named\fR <command> [name=value] ... Send command to Bitcoin Core (with named arguments)
|
||||
bitcoin\-cli [options] help List commands
|
||||
bitcoin\-cli [options] help <command> Get help for a command
|
||||
Bitcoin Core RPC client version v0.17.1.0
|
||||
.SH OPTIONS
|
||||
.HP
|
||||
\-?
|
||||
@@ -77,15 +81,13 @@ corresponding \fB\-wallet\fR option passed to bitcoind)
|
||||
\fB\-stdin\fR
|
||||
.IP
|
||||
Read extra arguments from standard input, one per line until EOF/Ctrl\-D
|
||||
(recommended for sensitive information such as passphrases).
|
||||
When combined with \fB\-stdinrpcpass\fR, the first line from standard
|
||||
input is used for the RPC password.
|
||||
(recommended for sensitive information such as passphrases). When
|
||||
combined with \fB\-stdinrpcpass\fR, the first line from standard input
|
||||
is used for the RPC password.
|
||||
.HP
|
||||
\fB\-stdinrpcpass\fR
|
||||
.TP
|
||||
Read RPC password from standard input as a single line.
|
||||
When combined
|
||||
.IP
|
||||
Read RPC password from standard input as a single line. When combined
|
||||
with \fB\-stdin\fR, the first line from standard input is used for the
|
||||
RPC password.
|
||||
.HP
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
|
||||
.TH BITCOIN-QT "1" "July 2018" "bitcoin-qt v0.16.99.0" "User Commands"
|
||||
.TH BITCOIN-QT "1" "December 2018" "bitcoin-qt v0.17.1.0" "User Commands"
|
||||
.SH NAME
|
||||
bitcoin-qt \- manual page for bitcoin-qt v0.16.99.0
|
||||
bitcoin-qt \- manual page for bitcoin-qt v0.17.1.0
|
||||
.SH SYNOPSIS
|
||||
.B bitcoin-qt
|
||||
[\fI\,command-line options\/\fR]
|
||||
.SH DESCRIPTION
|
||||
Bitcoin Core version v0.16.99.0 (64\-bit)
|
||||
Usage:
|
||||
.IP
|
||||
bitcoin\-qt [command\-line options]
|
||||
Bitcoin Core version v0.17.1.0 (64\-bit)
|
||||
.SH OPTIONS
|
||||
.HP
|
||||
\-?
|
||||
@@ -23,9 +23,9 @@ long fork (%s in cmd is replaced by message)
|
||||
If this block is in the chain assume that it and its ancestors are valid
|
||||
and potentially skip their script verification (0 to verify all,
|
||||
default:
|
||||
0000000000000000005214481d2d96f898e3d5416e43359c145944a909d242e0,
|
||||
0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8,
|
||||
testnet:
|
||||
0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1)
|
||||
0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75)
|
||||
.HP
|
||||
\fB\-blocknotify=\fR<cmd>
|
||||
.IP
|
||||
@@ -61,7 +61,8 @@ Set database cache size in megabytes (4 to 16384, default: 450)
|
||||
\fB\-debuglogfile=\fR<file>
|
||||
.IP
|
||||
Specify location of debug log file. Relative paths will be prefixed by a
|
||||
net\-specific datadir location. (0 to disable; default: debug.log)
|
||||
net\-specific datadir location. (\fB\-nodebuglogfile\fR to disable;
|
||||
default: debug.log)
|
||||
.HP
|
||||
\fB\-includeconf=\fR<file>
|
||||
.IP
|
||||
@@ -87,7 +88,7 @@ Do not keep transactions in the mempool longer than <n> hours (default:
|
||||
.HP
|
||||
\fB\-par=\fR<n>
|
||||
.IP
|
||||
Set the number of script verification threads (\fB\-8\fR to 16, 0 = auto, <0 =
|
||||
Set the number of script verification threads (\fB\-6\fR to 16, 0 = auto, <0 =
|
||||
leave that many cores free, default: 0)
|
||||
.HP
|
||||
\fB\-persistmempool\fR
|
||||
@@ -108,7 +109,7 @@ blocks if a target size in MiB is provided. This mode is
|
||||
incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
|
||||
setting requires re\-downloading the entire blockchain. (default:
|
||||
0 = disable pruning blocks, 1 = allow manual pruning via RPC,
|
||||
>550 = automatically prune block files to stay under the
|
||||
>=550 = automatically prune block files to stay under the
|
||||
specified target size in MiB)
|
||||
.HP
|
||||
\fB\-reindex\fR
|
||||
@@ -157,7 +158,7 @@ for IPv6
|
||||
.HP
|
||||
\fB\-connect=\fR<ip>
|
||||
.IP
|
||||
Connect only to the specified node; \fB\-connect\fR=\fI\,0\/\fR disables automatic
|
||||
Connect only to the specified node; \fB\-noconnect\fR disables automatic
|
||||
connections (the rules for this peer are the same as for
|
||||
\fB\-addnode\fR). This option can be specified multiple times to connect
|
||||
to multiple nodes.
|
||||
@@ -221,8 +222,8 @@ Tries to keep outbound traffic under the given target (in MiB per 24h),
|
||||
.HP
|
||||
\fB\-onion=\fR<ip:port>
|
||||
.IP
|
||||
Use separate SOCKS5 proxy to reach peers via Tor hidden services
|
||||
(default: \fB\-proxy\fR)
|
||||
Use separate SOCKS5 proxy to reach peers via Tor hidden services, set
|
||||
\fB\-noonion\fR to disable (default: \fB\-proxy\fR)
|
||||
.HP
|
||||
\fB\-onlynet=\fR<net>
|
||||
.IP
|
||||
@@ -246,7 +247,8 @@ Listen for connections on <port> (default: 8333 or testnet: 18333)
|
||||
.HP
|
||||
\fB\-proxy=\fR<ip:port>
|
||||
.IP
|
||||
Connect through SOCKS5 proxy
|
||||
Connect through SOCKS5 proxy, set \fB\-noproxy\fR to disable (default:
|
||||
disabled)
|
||||
.HP
|
||||
\fB\-proxyrandomize\fR
|
||||
.IP
|
||||
@@ -418,7 +420,7 @@ Debugging/Testing options:
|
||||
.HP
|
||||
\fB\-debug=\fR<category>
|
||||
.IP
|
||||
Output debugging information (default: 0, supplying <category> is
|
||||
Output debugging information (default: \fB\-nodebug\fR, supplying <category> is
|
||||
optional). If <category> is not supplied or if <category> = 1,
|
||||
output all debugging information. <category> can be: net, tor,
|
||||
mempool, http, bench, zmq, db, rpc, estimatefee, addrman,
|
||||
@@ -452,7 +454,7 @@ transaction; setting this too low may abort large transactions
|
||||
\fB\-printtoconsole\fR
|
||||
.IP
|
||||
Send trace/debug info to console (default: 1 when no \fB\-daemon\fR. To disable
|
||||
logging to file, set debuglogfile=0)
|
||||
logging to file, set \fB\-nodebuglogfile\fR)
|
||||
.HP
|
||||
\fB\-shrinkdebugfile\fR
|
||||
.IP
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
|
||||
.TH BITCOIN-TX "1" "July 2018" "bitcoin-tx v0.16.99.0" "User Commands"
|
||||
.TH BITCOIN-TX "1" "December 2018" "bitcoin-tx v0.17.1.0" "User Commands"
|
||||
.SH NAME
|
||||
bitcoin-tx \- manual page for bitcoin-tx v0.16.99.0
|
||||
bitcoin-tx \- manual page for bitcoin-tx v0.17.1.0
|
||||
.SH SYNOPSIS
|
||||
.B bitcoin-tx
|
||||
[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR] \fI\,Update hex-encoded bitcoin transaction\/\fR
|
||||
.br
|
||||
.B bitcoin-tx
|
||||
[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] \fI\,Create hex-encoded bitcoin transaction\/\fR
|
||||
.SH DESCRIPTION
|
||||
Bitcoin Core bitcoin\-tx utility version v0.16.99.0
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
bitcoin\-tx [options] <hex\-tx> [commands]
|
||||
Update hex\-encoded bitcoin transaction
|
||||
.TP
|
||||
bitcoin\-tx [options] \fB\-create\fR [commands]
|
||||
Create hex\-encoded bitcoin transaction
|
||||
Bitcoin Core bitcoin\-tx utility version v0.17.1.0
|
||||
.SH OPTIONS
|
||||
.HP
|
||||
\-?
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
|
||||
.TH BITCOIND "1" "July 2018" "bitcoind v0.16.99.0" "User Commands"
|
||||
.TH BITCOIND "1" "December 2018" "bitcoind v0.17.1.0" "User Commands"
|
||||
.SH NAME
|
||||
bitcoind \- manual page for bitcoind v0.16.99.0
|
||||
bitcoind \- manual page for bitcoind v0.17.1.0
|
||||
.SH SYNOPSIS
|
||||
.B bitcoind
|
||||
[\fI\,options\/\fR] \fI\,Start Bitcoin Core Daemon\/\fR
|
||||
.SH DESCRIPTION
|
||||
Bitcoin Core Daemon version v0.16.99.0
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
bitcoind [options]
|
||||
Start Bitcoin Core Daemon
|
||||
Bitcoin Core Daemon version v0.17.1.0
|
||||
.SH OPTIONS
|
||||
.HP
|
||||
\-?
|
||||
@@ -24,9 +23,9 @@ long fork (%s in cmd is replaced by message)
|
||||
If this block is in the chain assume that it and its ancestors are valid
|
||||
and potentially skip their script verification (0 to verify all,
|
||||
default:
|
||||
0000000000000000005214481d2d96f898e3d5416e43359c145944a909d242e0,
|
||||
0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8,
|
||||
testnet:
|
||||
0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1)
|
||||
0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75)
|
||||
.HP
|
||||
\fB\-blocknotify=\fR<cmd>
|
||||
.IP
|
||||
@@ -62,7 +61,8 @@ Set database cache size in megabytes (4 to 16384, default: 450)
|
||||
\fB\-debuglogfile=\fR<file>
|
||||
.IP
|
||||
Specify location of debug log file. Relative paths will be prefixed by a
|
||||
net\-specific datadir location. (0 to disable; default: debug.log)
|
||||
net\-specific datadir location. (\fB\-nodebuglogfile\fR to disable;
|
||||
default: debug.log)
|
||||
.HP
|
||||
\fB\-includeconf=\fR<file>
|
||||
.IP
|
||||
@@ -88,7 +88,7 @@ Do not keep transactions in the mempool longer than <n> hours (default:
|
||||
.HP
|
||||
\fB\-par=\fR<n>
|
||||
.IP
|
||||
Set the number of script verification threads (\fB\-8\fR to 16, 0 = auto, <0 =
|
||||
Set the number of script verification threads (\fB\-6\fR to 16, 0 = auto, <0 =
|
||||
leave that many cores free, default: 0)
|
||||
.HP
|
||||
\fB\-persistmempool\fR
|
||||
@@ -109,7 +109,7 @@ blocks if a target size in MiB is provided. This mode is
|
||||
incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
|
||||
setting requires re\-downloading the entire blockchain. (default:
|
||||
0 = disable pruning blocks, 1 = allow manual pruning via RPC,
|
||||
>550 = automatically prune block files to stay under the
|
||||
>=550 = automatically prune block files to stay under the
|
||||
specified target size in MiB)
|
||||
.HP
|
||||
\fB\-reindex\fR
|
||||
@@ -158,7 +158,7 @@ for IPv6
|
||||
.HP
|
||||
\fB\-connect=\fR<ip>
|
||||
.IP
|
||||
Connect only to the specified node; \fB\-connect\fR=\fI\,0\/\fR disables automatic
|
||||
Connect only to the specified node; \fB\-noconnect\fR disables automatic
|
||||
connections (the rules for this peer are the same as for
|
||||
\fB\-addnode\fR). This option can be specified multiple times to connect
|
||||
to multiple nodes.
|
||||
@@ -222,8 +222,8 @@ Tries to keep outbound traffic under the given target (in MiB per 24h),
|
||||
.HP
|
||||
\fB\-onion=\fR<ip:port>
|
||||
.IP
|
||||
Use separate SOCKS5 proxy to reach peers via Tor hidden services
|
||||
(default: \fB\-proxy\fR)
|
||||
Use separate SOCKS5 proxy to reach peers via Tor hidden services, set
|
||||
\fB\-noonion\fR to disable (default: \fB\-proxy\fR)
|
||||
.HP
|
||||
\fB\-onlynet=\fR<net>
|
||||
.IP
|
||||
@@ -247,7 +247,8 @@ Listen for connections on <port> (default: 8333 or testnet: 18333)
|
||||
.HP
|
||||
\fB\-proxy=\fR<ip:port>
|
||||
.IP
|
||||
Connect through SOCKS5 proxy
|
||||
Connect through SOCKS5 proxy, set \fB\-noproxy\fR to disable (default:
|
||||
disabled)
|
||||
.HP
|
||||
\fB\-proxyrandomize\fR
|
||||
.IP
|
||||
@@ -419,7 +420,7 @@ Debugging/Testing options:
|
||||
.HP
|
||||
\fB\-debug=\fR<category>
|
||||
.IP
|
||||
Output debugging information (default: 0, supplying <category> is
|
||||
Output debugging information (default: \fB\-nodebug\fR, supplying <category> is
|
||||
optional). If <category> is not supplied or if <category> = 1,
|
||||
output all debugging information. <category> can be: net, tor,
|
||||
mempool, http, bench, zmq, db, rpc, estimatefee, addrman,
|
||||
@@ -453,7 +454,7 @@ transaction; setting this too low may abort large transactions
|
||||
\fB\-printtoconsole\fR
|
||||
.IP
|
||||
Send trace/debug info to console (default: 1 when no \fB\-daemon\fR. To disable
|
||||
logging to file, set debuglogfile=0)
|
||||
logging to file, set \fB\-nodebuglogfile\fR)
|
||||
.HP
|
||||
\fB\-shrinkdebugfile\fR
|
||||
.IP
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
(note: this is a temporary file, to be added-to by anybody, and moved to
|
||||
release-notes at release time)
|
||||
Bitcoin Core version 0.17.1 is now available from:
|
||||
|
||||
Bitcoin Core version *version* is now available from:
|
||||
|
||||
<https://bitcoincore.org/bin/bitcoin-core-*version*/>
|
||||
<https://bitcoincore.org/bin/bitcoin-core-0.17.1/>
|
||||
|
||||
This is a new major version release, including new features, various bugfixes
|
||||
and performance improvements, as well as updated translations.
|
||||
@@ -24,7 +21,9 @@ shut down (which might take a few minutes for older versions), then run the
|
||||
installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
|
||||
or `bitcoind`/`bitcoin-qt` (on Linux).
|
||||
|
||||
The first time you run version 0.15.0, your chainstate database will be converted to a
|
||||
If your node has a txindex, the txindex db will be migrated the first time you run 0.17.0 or newer, which may take up to a few hours. Your node will not be functional until this migration completes.
|
||||
|
||||
The first time you run version 0.15.0 or newer, your chainstate database will be converted to a
|
||||
new format, which will take anywhere from a few minutes to half an hour,
|
||||
depending on the speed of your machine.
|
||||
|
||||
@@ -59,214 +58,107 @@ support versions of macOS older than 10.10.
|
||||
Notable changes
|
||||
===============
|
||||
|
||||
Changed command-line options
|
||||
----------------------------
|
||||
`listtransactions` label support
|
||||
--------------------------------
|
||||
|
||||
- `-includeconf=<file>` can be used to include additional configuration files.
|
||||
Only works inside the `bitcoin.conf` file, not inside included files or from
|
||||
command-line. Multiple files may be included. Can be disabled from command-
|
||||
line via `-noincludeconf`. Note that multi-argument commands like
|
||||
`-includeconf` will override preceding `-noincludeconf`, i.e.
|
||||
The `listtransactions` RPC `account` parameter which was deprecated in 0.17.0
|
||||
and renamed to `dummy` has been un-deprecated and renamed again to `label`.
|
||||
|
||||
noincludeconf=1
|
||||
includeconf=relative.conf
|
||||
When bitcoin is configured with the `-deprecatedrpc=accounts` setting, specifying
|
||||
a label/account/dummy argument will return both outgoing and incoming
|
||||
transactions. Without the `-deprecatedrpc=accounts` setting, it will only return
|
||||
incoming transactions (because it used to be possible to create transactions
|
||||
spending from specific accounts, but this is no longer possible with labels).
|
||||
|
||||
as bitcoin.conf will still include `relative.conf`.
|
||||
When `-deprecatedrpc=accounts` is set, it's possible to pass the empty string ""
|
||||
to list transactions that don't have any label. Without
|
||||
`-deprecatedrpc=accounts`, passing the empty string is an error because returning
|
||||
only non-labeled transactions is not generally useful behavior and can cause
|
||||
confusion.
|
||||
|
||||
GUI changes
|
||||
-----------
|
||||
0.17.1 change log
|
||||
=================
|
||||
|
||||
- Block storage can be limited under Preferences, in the Main tab. Undoing this setting requires downloading the full blockchain again. This mode is incompatible with -txindex and -rescan.
|
||||
### P2P protocol and network code
|
||||
- #14685 `9406502` Fix a deserialization overflow edge case (kazcw)
|
||||
- #14728 `b901578` Fix uninitialized read when stringifying an addrLocal (kazcw)
|
||||
|
||||
RPC changes
|
||||
------------
|
||||
### Wallet
|
||||
- #14441 `5150acc` Restore ability to list incoming transactions by label (jnewbery)
|
||||
- #13546 `91fa15a` Fix use of uninitialized value `bnb_used` in CWallet::CreateTransaction(…) (practicalswift)
|
||||
- #14310 `bb90695` Ensure wallet is unlocked before signing (gustavonalle)
|
||||
- #14690 `5782fdc` Throw error if CPubKey is invalid during PSBT keypath serialization (instagibbs)
|
||||
- #14852 `2528443` backport: [tests] Add `wallet_balance.py` (MarcoFalke)
|
||||
- #14196 `3362a95` psbt: always drop the unnecessary utxo and convert non-witness utxo to witness when necessary (achow101)
|
||||
- #14588 `70ee1f8` Refactor PSBT signing logic to enforce invariant and fix signing bug (gwillen)
|
||||
- #14424 `89a9a9d` Stop requiring imported pubkey to sign non-PKH schemes (sipa, MeshCollider)
|
||||
|
||||
### Low-level changes
|
||||
### RPC and other APIs
|
||||
- #14417 `fb9ad04` Fix listreceivedbyaddress not taking address as a string (etscrivner)
|
||||
- #14596 `de5e48a` Bugfix: RPC: Add `address_type` named param for createmultisig (luke-jr)
|
||||
- #14618 `9666dba` Make HTTP RPC debug logging more informative (practicalswift)
|
||||
- #14197 `7bee414` [psbt] Convert non-witness UTXOs to witness if witness sig created (achow101)
|
||||
- #14377 `a3fe125` Check that a separator is found for psbt inputs, outputs, and global map (achow101)
|
||||
- #14356 `7a590d8` Fix converttopsbt permitsigdata arg, add basic test (instagibbs)
|
||||
- #14453 `75b5d8c` Fix wallet unload during walletpassphrase timeout (promag)
|
||||
|
||||
- The `createrawtransaction` RPC will now accept an array or dictionary (kept for compatibility) for the `outputs` parameter. This means the order of transaction outputs can be specified by the client.
|
||||
- The `fundrawtransaction` RPC will reject the previously deprecated `reserveChangeKey` option.
|
||||
- `sendmany` now shuffles outputs to improve privacy, so any previously expected behavior with regards to output ordering can no longer be relied upon.
|
||||
- The new RPC `testmempoolaccept` can be used to test acceptance of a transaction to the mempool without adding it.
|
||||
- JSON transaction decomposition now includes a `weight` field which provides
|
||||
the transaction's exact weight. This is included in REST /rest/tx/ and
|
||||
/rest/block/ endpoints when in json mode. This is also included in `getblock`
|
||||
(with verbosity=2), `listsinceblock`, `listtransactions`, and
|
||||
`getrawtransaction` RPC commands.
|
||||
- New `fees` field introduced in `getrawmempool`, `getmempoolancestors`, `getmempooldescendants` and
|
||||
`getmempoolentry` when verbosity is set to `true` with sub-fields `ancestor`, `base`, `modified`
|
||||
and `descendant` denominated in BTC. This new field deprecates previous fee fields, such as
|
||||
`fee`, `modifiedfee`, `ancestorfee` and `descendantfee`.
|
||||
- The new RPC `getzmqnotifications` returns information about active ZMQ
|
||||
notifications.
|
||||
### GUI
|
||||
- #14403 `0242b5a` Revert "Force TLS1.0+ for SSL connections" (real-or-random)
|
||||
- #14593 `df5131b` Explicitly disable "Dark Mode" appearance on macOS (fanquake)
|
||||
|
||||
External wallet files
|
||||
---------------------
|
||||
### Build system
|
||||
- #14647 `7edebed` Remove illegal spacing in darwin.mk (ch4ot1c)
|
||||
- #14698 `ec71f06` Add bitcoin-tx.exe into Windows installer (ken2812221)
|
||||
|
||||
The `-wallet=<path>` option now accepts full paths instead of requiring wallets
|
||||
to be located in the -walletdir directory.
|
||||
### Tests and QA
|
||||
- #13965 `29899ec` Fix extended functional tests fail (ken2812221)
|
||||
- #14011 `9461f98` Disable wallet and address book Qt tests on macOS minimal platform (ryanofsky)
|
||||
- #14180 `86fadee` Run all tests even if wallet is not compiled (MarcoFalke)
|
||||
- #14122 `8bc1bad` Test `rpc_help.py` failed: Check whether ZMQ is enabled or not (Kvaciral)
|
||||
- #14101 `96dc936` Use named args in validation acceptance tests (MarcoFalke)
|
||||
- #14020 `24d796a` Add tests for RPC help (promag)
|
||||
- #14052 `7ff32a6` Add some actual witness in `rpc_rawtransaction` (MarcoFalke)
|
||||
- #14215 `b72fbab` Use correct python index slices in example test (sdaftuar)
|
||||
- #14024 `06544fa` Add `TestNode::assert_debug_log` (MarcoFalke)
|
||||
- #14658 `60f7a97` Add test to ensure node can generate all rpc help texts at runtime (MarcoFalke)
|
||||
- #14632 `96f15e8` Fix a comment (fridokus)
|
||||
- #14700 `f9db08e` Avoid race in `p2p_invalid_block` by waiting for the block request (MarcoFalke)
|
||||
- #14845 `67225e2` Add `wallet_balance.py` (jnewbery)
|
||||
|
||||
Newly created wallet format
|
||||
---------------------------
|
||||
|
||||
If `-wallet=<path>` is specified with a path that does not exist, it will now
|
||||
create a wallet directory at the specified location (containing a wallet.dat
|
||||
data file, a db.log file, and database/log.?????????? files) instead of just
|
||||
creating a data file at the path and storing log files in the parent
|
||||
directory. This should make backing up wallets more straightforward than
|
||||
before because the specified wallet path can just be directly archived without
|
||||
having to look in the parent directory for transaction log files.
|
||||
|
||||
For backwards compatibility, wallet paths that are names of existing data files
|
||||
in the `-walletdir` directory will continue to be accepted and interpreted the
|
||||
same as before.
|
||||
|
||||
Dynamic loading and creation of wallets
|
||||
---------------------------------------
|
||||
|
||||
Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load, create and unload wallets dynamically at runtime:
|
||||
|
||||
- Existing wallets can be loaded by calling the `loadwallet` RPC. The wallet can be specified as file/directory basename (which must be located in the `walletdir` directory), or as an absolute path to a file/directory.
|
||||
- New wallets can be created (and loaded) by calling the `createwallet` RPC. The provided name must not match a wallet file in the `walletdir` directory or the name of a wallet that is currently loaded.
|
||||
- Loaded wallets can be unloaded by calling the `unloadwallet` RPC.
|
||||
|
||||
This feature is currently only available through the RPC interface.
|
||||
|
||||
Coin selection
|
||||
--------------
|
||||
- A new `-avoidpartialspends` flag has been added (default=false). If enabled, the wallet will try to spend UTXO's that point at the same destination
|
||||
together. This is a privacy increase, as there will no longer be cases where a wallet will inadvertently spend only parts of the coins sent to
|
||||
the same address (note that if someone were to send coins to that address after it was used, those coins will still be included in future
|
||||
coin selections).
|
||||
|
||||
Configuration sections for testnet and regtest
|
||||
----------------------------------------------
|
||||
|
||||
It is now possible for a single configuration file to set different
|
||||
options for different networks. This is done by using sections or by
|
||||
prefixing the option with the network, such as:
|
||||
|
||||
main.uacomment=bitcoin
|
||||
test.uacomment=bitcoin-testnet
|
||||
regtest.uacomment=regtest
|
||||
[main]
|
||||
mempoolsize=300
|
||||
[test]
|
||||
mempoolsize=100
|
||||
[regtest]
|
||||
mempoolsize=20
|
||||
|
||||
The `addnode=`, `connect=`, `port=`, `bind=`, `rpcport=`, `rpcbind=`
|
||||
and `wallet=` options will only apply to mainnet when specified in the
|
||||
configuration file, unless a network is specified.
|
||||
|
||||
'label' and 'account' APIs for wallet
|
||||
-------------------------------------
|
||||
|
||||
A new 'label' API has been introduced for the wallet. This is intended as a
|
||||
replacement for the deprecated 'account' API. The 'account' can continue to
|
||||
be used in V0.17 by starting bitcoind with the '-deprecatedrpc=accounts'
|
||||
argument, and will be fully removed in V0.18.
|
||||
|
||||
The label RPC methods mirror the account functionality, with the following functional differences:
|
||||
|
||||
- Labels can be set on any address, not just receiving addresses. This functionality was previously only available through the GUI.
|
||||
- Labels can be deleted by reassigning all addresses using the `setlabel` RPC method.
|
||||
- There isn't support for sending transactions _from_ a label, or for determining which label a transaction was sent from.
|
||||
- Labels do not have a balance.
|
||||
|
||||
Here are the changes to RPC methods:
|
||||
|
||||
| Deprecated Method | New Method | Notes |
|
||||
| :---------------------- | :-------------------- | :-----------|
|
||||
| `getaccount` | `getaddressinfo` | `getaddressinfo` returns a json object with address information instead of just the name of the account as a string. |
|
||||
| `getaccountaddress` | n/a | There is no replacement for `getaccountaddress` since labels do not have an associated receive address. |
|
||||
| `getaddressesbyaccount` | `getaddressesbylabel` | `getaddressesbylabel` returns a json object with the addresses as keys, instead of a list of strings. |
|
||||
| `getreceivedbyaccount` | `getreceivedbylabel` | _no change in behavior_ |
|
||||
| `listaccounts` | `listlabels` | `listlabels` does not return a balance or accept `minconf` and `watchonly` arguments. |
|
||||
| `listreceivedbyaccount` | `listreceivedbylabel` | Both methods return new `label` fields, along with `account` fields for backward compatibility. |
|
||||
| `move` | n/a | _no replacement_ |
|
||||
| `sendfrom` | n/a | _no replacement_ |
|
||||
| `setaccount` | `setlabel` | Both methods now: <ul><li>allow assigning labels to any address, instead of raising an error if the address is not receiving address.<li>delete the previous label associated with an address when the final address using that label is reassigned to a different label, instead of making an implicit `getaccountaddress` call to ensure the previous label still has a receiving address. |
|
||||
|
||||
| Changed Method | Notes |
|
||||
| :--------------------- | :------ |
|
||||
| `addmultisigaddress` | Renamed `account` named parameter to `label`. Still accepts `account` for backward compatibility if running with '-deprecatedrpc=accounts'. |
|
||||
| `getnewaddress` | Renamed `account` named parameter to `label`. Still accepts `account` for backward compatibility. if running with '-deprecatedrpc=accounts' |
|
||||
| `listunspent` | Returns new `label` fields. `account` field will be returned for backward compatibility if running with '-deprecatedrpc=accounts' |
|
||||
| `sendmany` | The `account` named parameter has been renamed to `dummy`. If provided, the `dummy` parameter must be set to the empty string, unless running with the `-deprecatedrpc=accounts` argument (in which case functionality is unchanged). |
|
||||
| `listtransactions` | The `account` named parameter has been renamed to `dummy`. If provided, the `dummy` parameter must be set to the string `*`, unless running with the `-deprecatedrpc=accounts` argument (in which case functionality is unchanged). |
|
||||
| `getbalance` | `account`, `minconf` and `include_watchonly` parameters are deprecated, and can only be used if running with '-deprecatedrpc=accounts' |
|
||||
|
||||
Low-level RPC changes
|
||||
---------------------
|
||||
|
||||
- When bitcoin is not started with any `-wallet=<path>` options, the name of
|
||||
the default wallet returned by `getwalletinfo` and `listwallets` RPCs is
|
||||
now the empty string `""` instead of `"wallet.dat"`. If bitcoin is started
|
||||
with any `-wallet=<path>` options, there is no change in behavior, and the
|
||||
name of any wallet is just its `<path>` string.
|
||||
- Passing an empty string (`""`) as the `address_type` parameter to
|
||||
`getnewaddress`, `getrawchangeaddress`, `addmultisigaddress`,
|
||||
`fundrawtransaction` RPCs is now an error. Previously, this would fall back
|
||||
to using the default address type. It is still possible to pass null or leave
|
||||
the parameter unset to use the default address type.
|
||||
|
||||
- Bare multisig outputs to our keys are no longer automatically treated as
|
||||
incoming payments. As this feature was only available for multisig outputs for
|
||||
which you had all private keys in your wallet, there was generally no use for
|
||||
them compared to single-key schemes. Furthermore, no address format for such
|
||||
outputs is defined, and wallet software can't easily send to it. These outputs
|
||||
will no longer show up in `listtransactions`, `listunspent`, or contribute to
|
||||
your balance, unless they are explicitly watched (using `importaddress` or
|
||||
`importmulti` with hex script argument). `signrawtransaction*` also still
|
||||
works for them.
|
||||
|
||||
- The `getwalletinfo` RPC method now returns an `hdseedid` value, which is always the same as the incorrectly-named `hdmasterkeyid` value. `hdmasterkeyid` will be removed in V0.18.
|
||||
- The `getaddressinfo` RPC method now returns an `hdseedid` value, which is always the same as the incorrectly-named `hdmasterkeyid` value. `hdmasterkeyid` will be removed in V0.18.
|
||||
|
||||
Other API changes
|
||||
-----------------
|
||||
|
||||
- The `inactivehdmaster` property in the `dumpwallet` output has been corrected to `inactivehdseed`
|
||||
|
||||
### Logging
|
||||
|
||||
- The log timestamp format is now ISO 8601 (e.g. "2018-02-28T12:34:56Z").
|
||||
|
||||
- When running bitcoind with `-debug` but without `-daemon`, logging to stdout
|
||||
is now the default behavior. Setting `-printtoconsole=1` no longer implicitly
|
||||
disables logging to debug.log. Instead, logging to file can be explicitly disabled
|
||||
by setting `-debuglogfile=0`.
|
||||
|
||||
Transaction index changes
|
||||
-------------------------
|
||||
|
||||
The transaction index is now built separately from the main node procedure,
|
||||
meaning the `-txindex` flag can be toggled without a full reindex. If bitcoind
|
||||
is run with `-txindex` on a node that is already partially or fully synced
|
||||
without one, the transaction index will be built in the background and become
|
||||
available once caught up. When switching from running `-txindex` to running
|
||||
without the flag, the transaction index database will *not* be deleted
|
||||
automatically, meaning it could be turned back on at a later time without a full
|
||||
resync.
|
||||
|
||||
Miner block size removed
|
||||
------------------------
|
||||
|
||||
The `-blockmaxsize` option for miners to limit their blocks' sizes was
|
||||
deprecated in V0.15.1, and has now been removed. Miners should use the
|
||||
`-blockmaxweight` option if they want to limit the weight of their blocks'
|
||||
weights.
|
||||
|
||||
Python Support
|
||||
--------------
|
||||
|
||||
Support for Python 2 has been discontinued for all test files and tools.
|
||||
### Documentation
|
||||
- #14161 `5f51fd6` doc/descriptors.md tweaks (ryanofsky)
|
||||
- #14276 `85aacc4` Add autogen.sh in ARM Cross-compilation (walterwhite81)
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Thanks to everyone who directly contributed to this release:
|
||||
|
||||
- Andrew Chow
|
||||
- Chun Kuan Lee
|
||||
- David A. Harding
|
||||
- Eric Scrivner
|
||||
- fanquake
|
||||
- fridokus
|
||||
- Glenn Willen
|
||||
- Gregory Sanders
|
||||
- gustavonalle
|
||||
- John Newbery
|
||||
- Jon Layton
|
||||
- Jonas Schnelli
|
||||
- João Barbosa
|
||||
- Kaz Wesley
|
||||
- Kvaciral
|
||||
- Luke Dashjr
|
||||
- MarcoFalke
|
||||
- MeshCollider
|
||||
- Pieter Wuille
|
||||
- practicalswift
|
||||
- Russell Yanofsky
|
||||
- Sjors Provoost
|
||||
- Suhas Daftuar
|
||||
- Tim Ruffing
|
||||
- Walter
|
||||
- Wladimir J. van der Laan
|
||||
|
||||
As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
|
||||
<key>LSAppNapIsDisabled</key>
|
||||
<string>True</string>
|
||||
|
||||
<key>NSRequiresAquaSystemAppearance</key>
|
||||
<string>True</string>
|
||||
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.finance</string>
|
||||
|
||||
@@ -80,8 +80,9 @@ Section -Main SEC0000
|
||||
SetOutPath $INSTDIR\daemon
|
||||
File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@
|
||||
File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@
|
||||
File @abs_top_srcdir@/release/@BITCOIN_TX_NAME@@EXEEXT@
|
||||
SetOutPath $INSTDIR\doc
|
||||
File /r @abs_top_srcdir@/doc\*.*
|
||||
File /r /x Makefile* @abs_top_srcdir@/doc\*.*
|
||||
SetOutPath $INSTDIR
|
||||
WriteRegStr HKCU "${REGKEY}\Components" Main 1
|
||||
SectionEnd
|
||||
|
||||
@@ -52,12 +52,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t offset = 0;
|
||||
int32_t offset = 0;
|
||||
for (size_t j = 0; j < indexes.size(); j++) {
|
||||
if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
|
||||
if (int32_t(indexes[j]) + offset > std::numeric_limits<uint16_t>::max())
|
||||
throw std::ios_base::failure("indexes overflowed 16 bits");
|
||||
indexes[j] = indexes[j] + offset;
|
||||
offset = indexes[j] + 1;
|
||||
offset = int32_t(indexes[j]) + 1;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < indexes.size(); i++) {
|
||||
@@ -186,6 +186,9 @@ public:
|
||||
|
||||
READWRITE(prefilledtxn);
|
||||
|
||||
if (BlockTxCount() > std::numeric_limits<uint16_t>::max())
|
||||
throw std::ios_base::failure("indexes overflowed 16 bits");
|
||||
|
||||
if (ser_action.ForRead())
|
||||
FillShortTxIDSelector();
|
||||
}
|
||||
|
||||
@@ -224,21 +224,25 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
|
||||
}
|
||||
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
|
||||
|
||||
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
|
||||
RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
|
||||
|
||||
// Early address-based allow check
|
||||
if (!ClientAllowed(hreq->GetPeer())) {
|
||||
LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n",
|
||||
hreq->GetPeer().ToString());
|
||||
hreq->WriteReply(HTTP_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
// Early reject unknown HTTP methods
|
||||
if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
|
||||
LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
|
||||
hreq->GetPeer().ToString());
|
||||
hreq->WriteReply(HTTP_BADMETHOD);
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
|
||||
RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString());
|
||||
|
||||
// Find registered handler for prefix
|
||||
std::string strURI = hreq->GetURI();
|
||||
std::string path;
|
||||
|
||||
12
src/init.cpp
12
src/init.cpp
@@ -366,7 +366,7 @@ void SetupServerArgs()
|
||||
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (0 to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-loadblock=<file>", "Imports blocks from external blk000??.dat file on startup", false, OptionsCategory::OPTIONS);
|
||||
@@ -398,7 +398,7 @@ void SetupServerArgs()
|
||||
gArgs.AddArg("-banscore=<n>", strprintf("Threshold for disconnecting misbehaving peers (default: %u)", DEFAULT_BANSCORE_THRESHOLD), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-bantime=<n>", strprintf("Number of seconds to keep misbehaving peers from reconnecting (default: %u)", DEFAULT_MISBEHAVING_BANTIME), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-bind=<addr>", "Bind to given address and always listen on it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-connect=<ip>", "Connect only to the specified node; -connect=0 disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-dnsseed", "Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)", false, OptionsCategory::CONNECTION);
|
||||
@@ -412,12 +412,12 @@ void SetupServerArgs()
|
||||
gArgs.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor hidden services, set -noonion to disable (default: -proxy)", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u or testnet: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION);
|
||||
gArgs.AddArg("-timeout=<n>", strprintf("Specify connection timeout in milliseconds (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), false, OptionsCategory::CONNECTION);
|
||||
@@ -465,7 +465,7 @@ void SetupServerArgs()
|
||||
gArgs.AddArg("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT), true, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", true, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-addrmantest", "Allows to test address relay on localhost", true, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-debug=<category>", strprintf("Output debugging information (default: %u, supplying <category> is optional)", 0) + ". " +
|
||||
gArgs.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). "
|
||||
"If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-help-debug", "Show all debugging options (usage: --help -help-debug)", false, OptionsCategory::DEBUG_TEST);
|
||||
@@ -478,7 +478,7 @@ void SetupServerArgs()
|
||||
gArgs.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)",
|
||||
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set debuglogfile=0)", false, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", false, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", false, OptionsCategory::DEBUG_TEST);
|
||||
gArgs.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", false, OptionsCategory::DEBUG_TEST);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87,
|
||||
CNetAddr::CNetAddr()
|
||||
{
|
||||
memset(ip, 0, sizeof(ip));
|
||||
scopeId = 0;
|
||||
}
|
||||
|
||||
void CNetAddr::SetIP(const CNetAddr& ipIn)
|
||||
|
||||
@@ -33,7 +33,7 @@ class CNetAddr
|
||||
{
|
||||
protected:
|
||||
unsigned char ip[16]; // in network byte order
|
||||
uint32_t scopeId; // for scoped/link-local ipv6 addresses
|
||||
uint32_t scopeId{0}; // for scoped/link-local ipv6 addresses
|
||||
|
||||
public:
|
||||
CNetAddr();
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
#include <QSslConfiguration>
|
||||
|
||||
#if defined(QT_STATICPLUGIN)
|
||||
#include <QtPlugin>
|
||||
@@ -576,13 +575,6 @@ int main(int argc, char *argv[])
|
||||
#ifdef Q_OS_MAC
|
||||
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
|
||||
#endif
|
||||
#if QT_VERSION >= 0x050500
|
||||
// Because of the POODLE attack it is recommended to disable SSLv3 (https://disablessl3.com/),
|
||||
// so set SSL protocols to TLS1.0+.
|
||||
QSslConfiguration sslconf = QSslConfiguration::defaultConfiguration();
|
||||
sslconf.setProtocol(QSsl::TlsV1_0OrLater);
|
||||
QSslConfiguration::setDefaultConfiguration(sslconf);
|
||||
#endif
|
||||
|
||||
// Register meta types used for QMetaObject::invokeMethod
|
||||
qRegisterMetaType< bool* >();
|
||||
|
||||
@@ -3199,6 +3199,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos
|
||||
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
|
||||
<translation>Fejl under læsning af %s! Alle nøgler blev læst korrekt, men transaktionsdata eller indgange i adressebogen kan mangle eller være ukorrekte.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
|
||||
<translation>Gruppér output efter adresse og vælg alle eller ingen, i stedet for at vælge på per-output-basis. Højere sikring af privatliv, da en adresse kun bruges én gang (med mindre nogen sender til en adresse efter den er brugt), men kan resultere i en anelse højere gebyrer, da ikke-optimal valg af output-adresser kan forekomme på grund af den tilføjede begrænsning (standard: %u)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
|
||||
<translation>Undersøg venligst at din computers dato og klokkeslet er korrekt indstillet! Hvis der er fejl i disse, vil %s ikke fungere korrekt.</translation>
|
||||
@@ -3339,6 +3343,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos
|
||||
<source>Invalid amount for -fallbackfee=<amount>: '%s'</source>
|
||||
<translation>Ugyldigt beløb for -fallbackfee=<beløb>: “%s”</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.</source>
|
||||
<translation>Angivet blokmappe “%s” eksisterer ikke.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Upgrading txindex database</source>
|
||||
<translation>Opgraderer txindex database</translation>
|
||||
@@ -3479,12 +3487,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos
|
||||
<source>Signing transaction failed</source>
|
||||
<translation>Signering af transaktion mislykkedes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Specificeret blokke mappe "%s" eksisterer ikke.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Transaktionsbeløbet er for lille til at betale gebyret</translation>
|
||||
|
||||
@@ -3336,6 +3336,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio
|
||||
<source>Invalid amount for -fallbackfee=<amount>: '%s'</source>
|
||||
<translation>Ungültiger Betrag für -fallbackfee=<amount>: '%s'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.</source>
|
||||
<translation>Angegebener Blöcke-Ordner "%s" existiert nicht.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Upgrading txindex database</source>
|
||||
<translation>Erneuern der txindex Datenbank</translation>
|
||||
@@ -3484,12 +3488,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>Angegebenes Verzeichniss "%s" ist kein Verzeichniss</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Angegebenes 'blocks'-Verzeichnis "%s" existiert nicht.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Der Transaktionsbetrag ist zu niedrig, um die Gebühr zu bezahlen.</translation>
|
||||
|
||||
@@ -610,6 +610,14 @@
|
||||
<source>Copy transaction ID</source>
|
||||
<translation>Αντιγραφή ταυτότητας συναλλαγής</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy quantity</source>
|
||||
<translation>Αντιγραφή ποσότητας</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy fee</source>
|
||||
<translation>Αντιγραφή τελών</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>yes</source>
|
||||
<translation>ναι</translation>
|
||||
@@ -661,7 +669,27 @@
|
||||
<source>Edit sending address</source>
|
||||
<translation> Επεξεργασία διεύθυνσης αποστολής</translation>
|
||||
</message>
|
||||
</context>
|
||||
<message>
|
||||
<source>The entered address "%1" is not a valid Bitcoin address.</source>
|
||||
<translation>Η διεύθυνση "%1" δεν είναι έγκυρη Bitcoin διεύθυνση.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
|
||||
<translation>Η διεύθυνση "%1" υπάρχει ήδη ως διεύθυνσης λήψης με ετικέτα "%2" και γιαυτό τον λόγο δεν μπορεί να προστεθεί ως διεύθυνση αποστολής.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The entered address "%1" is already in the address book with label "%2".</source>
|
||||
<translation>Η διεύθυνση "%1" βρίσκεται ήδη στο βιβλίο διευθύνσεων με ετικέτα "%2".</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not unlock wallet.</source>
|
||||
<translation>Δεν είναι δυνατό το ξεκλείδωμα του πορτοφολιού.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>New key generation failed.</source>
|
||||
<translation>Η δημιουργία νέου κλειδιού απέτυχε.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FreespaceChecker</name>
|
||||
<message>
|
||||
@@ -1488,10 +1516,18 @@
|
||||
<source>S&end</source>
|
||||
<translation>Αποστολή</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy quantity</source>
|
||||
<translation>Αντιγραφή ποσότητας</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy amount</source>
|
||||
<translation>Αντιγραφή ποσού</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy fee</source>
|
||||
<translation>Αντιγραφή τελών</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Transaction fee</source>
|
||||
<translation>Κόστος συναλλαγής</translation>
|
||||
|
||||
@@ -3490,12 +3490,6 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>El -walletdir "%s" indicado no es un directorio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>El directorio de bloques especificado "%s" no existe.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Cantidad de la transacción demasiado pequeña para pagar la comisión</translation>
|
||||
|
||||
@@ -325,6 +325,14 @@
|
||||
<source>Open &URI...</source>
|
||||
<translation>Avaa &URI...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wallet:</source>
|
||||
<translation>Lompakko:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>default wallet</source>
|
||||
<translation>oletuslompakko</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click to disable network activity.</source>
|
||||
<translation>Paina poistaaksesi verkkoyhteysilmaisin käytöstä.</translation>
|
||||
@@ -345,6 +353,10 @@
|
||||
<source>Reindexing blocks on disk...</source>
|
||||
<translation>Ladataan lohkoindeksiä...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Proxy is <b>enabled</b>: %1</source>
|
||||
<translation>Välipalvelin on <b>käytössä</b>: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Send coins to a Bitcoin address</source>
|
||||
<translation>Lähetä kolikoita Bitcoin-osoitteeseen</translation>
|
||||
@@ -441,6 +453,10 @@
|
||||
<source>&Command-line options</source>
|
||||
<translation>&Komentorivin valinnat</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>%n active connection(s) to Bitcoin network</source>
|
||||
<translation><numerusform>%n aktiivinen yhteys Bitcoin-verkkoon</numerusform><numerusform>%n aktiivista yhteyttä Bitcoin-verkkoon</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Indexing blocks on disk...</source>
|
||||
<translation>Ladataan lohkoindeksiä...</translation>
|
||||
@@ -449,6 +465,10 @@
|
||||
<source>Processing blocks on disk...</source>
|
||||
<translation>Käsitellään lohkoja levyllä...</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>Processed %n block(s) of transaction history.</source>
|
||||
<translation><numerusform>Käsitelty %n lohko rahansiirtohistoriasta.</numerusform><numerusform>Käsitelty %n lohkoa rahansiirtohistoriasta.</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 behind</source>
|
||||
<translation>%1 jäljessä</translation>
|
||||
@@ -1708,6 +1728,10 @@
|
||||
<source>&Unban</source>
|
||||
<translation>&Poista esto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>default wallet</source>
|
||||
<translation>oletuslompakko</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to the %1 RPC console.</source>
|
||||
<translation>Tervetuloa %1 RPC-konsoliin.</translation>
|
||||
|
||||
@@ -3479,12 +3479,6 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
|
||||
<source>Signing transaction failed</source>
|
||||
<translation>Échec de signature de la transaction</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Le répertoire de blocs indiqué « %s » n’existe pas.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Le montant de la transaction est trop bas pour que les frais soient payés</translation>
|
||||
|
||||
@@ -3199,6 +3199,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
|
||||
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
|
||||
<translation>%s の読み込みエラー! すべてのキーは正しく読み取れますが、取引データやアドレス帳のエントリが失われたか、正しくない可能性があります。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
|
||||
<translation>出力ごとではなく、アドレス単位に出力をまとめて選択します。(後からまたそのアドレスに支払われない限り)アドレスが一度しか使用されないためプライバシーが向上します。ただし追加の制限により最適ではないコイン選択が発生した場合に、わずかに高い手数料となる可能性があります。(初期値: %u)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
|
||||
<translation>あなたのPCの日付と時刻が正しいことを確認して下さい! もしあなたの時計が正しくなければ %s が正確に動作しません。</translation>
|
||||
@@ -3340,6 +3344,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
|
||||
<source>Invalid amount for -fallbackfee=<amount>: '%s'</source>
|
||||
<translation>不正な額 -fallbackfee=<amount>: '%s'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.</source>
|
||||
<translation>指定のブロックディレクトリ"%s"は存在しません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Upgrading txindex database</source>
|
||||
<translation>txindex データベースを更新しています</translation>
|
||||
@@ -3480,12 +3488,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
|
||||
<source>Signing transaction failed</source>
|
||||
<translation>取引の署名に失敗しました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>指定のブロックディレクトリ"%s"が存在しません。
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>トランザクションの金額が小さすぎて手数料を支払えません</translation>
|
||||
|
||||
@@ -3488,11 +3488,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>애러: 지정한 지갑 폴더 "%s"은 디렉토리가 아닙니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>지정한 블록 폴더 "%s"는 존재하지 않습니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>거래액이 수수료를 지불하기엔 너무 작습니다</translation>
|
||||
|
||||
@@ -3491,12 +3491,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>Opgegeven -walletdir "%s" is geen map</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Opgegeven blocks map "%s" bestaat niet.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Het transactiebedrag is te klein om transactiekosten in rekening te brengen</translation>
|
||||
|
||||
@@ -3493,12 +3493,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>Podany -walletdir "%s" nie jest katalogiem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Podany folder bloków "%s" nie istnieje.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Zbyt niska kwota transakcji by zapłacić opłatę</translation>
|
||||
|
||||
@@ -3335,6 +3335,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por
|
||||
<source>Invalid amount for -fallbackfee=<amount>: '%s'</source>
|
||||
<translation>Quantidade inválida para -fallbackfee=<amount>: '%s'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.</source>
|
||||
<translation>
|
||||
Diretório de blocos especificados "%s" não existe.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Upgrading txindex database</source>
|
||||
<translation>Atualizando banco de dados txindex</translation>
|
||||
@@ -3487,12 +3492,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>O -walletdir "%s" especificado não é um diretório</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>O diretório de blocos especificado "%s" não existe.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>A quantidade da transação é pequena demais para pagar a taxa</translation>
|
||||
|
||||
@@ -325,6 +325,14 @@
|
||||
<source>Open &URI...</source>
|
||||
<translation>Deschide &URI...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wallet:</source>
|
||||
<translation>Portofel:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>default wallet</source>
|
||||
<translation>portofel implicit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click to disable network activity.</source>
|
||||
<translation>Click pentru a opri activitatea retelei.</translation>
|
||||
@@ -345,6 +353,10 @@
|
||||
<source>Reindexing blocks on disk...</source>
|
||||
<translation>Se reindexează blocurile pe disc...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Proxy is <b>enabled</b>: %1</source>
|
||||
<translation>Proxy este<b>activat</b>:%1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Send coins to a Bitcoin address</source>
|
||||
<translation>Trimite monede către o adresă Bitcoin</translation>
|
||||
@@ -511,6 +523,12 @@
|
||||
<source>Amount: %1
|
||||
</source>
|
||||
<translation>Sumă: %1
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wallet: %1
|
||||
</source>
|
||||
<translation>Portofel: %1
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -745,6 +763,14 @@
|
||||
<source>The entered address "%1" is not a valid Bitcoin address.</source>
|
||||
<translation>Adresa introdusă "%1" nu este o adresă Bitcoin validă.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
|
||||
<translation>Adresa "%1" exista deja ca si adresa de primire cu eticheta "%2" si deci nu poate fi folosita ca si adresa de trimitere.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The entered address "%1" is already in the address book with label "%2".</source>
|
||||
<translation>Adresa introdusa "%1" este deja in lista de adrese cu eticheta "%2"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not unlock wallet.</source>
|
||||
<translation>Portofelul nu a putut fi deblocat.</translation>
|
||||
@@ -1748,6 +1774,10 @@
|
||||
<source>&Unban</source>
|
||||
<translation>&Unban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>default wallet</source>
|
||||
<translation>portofel implicit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to the %1 RPC console.</source>
|
||||
<translation>Bun venit la consola %1 RPC.</translation>
|
||||
|
||||
@@ -3436,12 +3436,6 @@
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>Uvedený -walletdir "%s" nie je priečinok</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Uvedený priečinok s dátami "%s" neexistuje.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Suma transakcie je príliš malá na zaplatenie poplatku</translation>
|
||||
|
||||
@@ -3477,12 +3477,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>Вказаний шлях -walletdir "%s" не є каталогом</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>Вказаний шлях до блоків "%s" не існує
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>Неможливо сплатити комісію із-за малої суми транзакції</translation>
|
||||
|
||||
@@ -3487,12 +3487,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
|
||||
<source>Specified -walletdir "%s" is not a directory</source>
|
||||
<translation>以 -walletdir 指定的路徑 "%s" 不是個目錄</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specified blocks directory "%s" does not exist.
|
||||
</source>
|
||||
<translation>指定的區塊目錄 "%s" 不存在。
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The transaction amount is too small to pay the fee</source>
|
||||
<translation>交易金額太少而付不起手續費</translation>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <key_io.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
@@ -139,5 +140,16 @@ void TestAddAddressesToSendBook()
|
||||
|
||||
void AddressBookTests::addressBookTests()
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
if (QApplication::platformName() == "minimal") {
|
||||
// Disable for mac on "minimal" platform to avoid crashes inside the Qt
|
||||
// framework when it tries to look up unimplemented cocoa functions,
|
||||
// and fails to handle returned nulls
|
||||
// (https://bugreports.qt.io/browse/QTBUG-49686).
|
||||
QWARN("Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
|
||||
"with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
TestAddAddressesToSendBook();
|
||||
}
|
||||
|
||||
@@ -243,5 +243,16 @@ void TestGUI()
|
||||
|
||||
void WalletTests::walletTests()
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
if (QApplication::platformName() == "minimal") {
|
||||
// Disable for mac on "minimal" platform to avoid crashes inside the Qt
|
||||
// framework when it tries to look up unimplemented cocoa functions,
|
||||
// and fails to handle returned nulls
|
||||
// (https://bugreports.qt.io/browse/QTBUG-49686).
|
||||
QWARN("Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
|
||||
"with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
TestGUI();
|
||||
}
|
||||
|
||||
@@ -2045,7 +2045,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
|
||||
"or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
|
||||
"unhardened or hardened child keys.\n"
|
||||
"In the latter case, a range needs to be specified by below if different from 1000.\n"
|
||||
"For more information on output descriptors, see the documentation at TODO\n"
|
||||
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"action\" (string, required) The action to execute\n"
|
||||
" \"start\" for starting a scan\n"
|
||||
|
||||
@@ -45,7 +45,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "listreceivedbyaddress", 0, "minconf" },
|
||||
{ "listreceivedbyaddress", 1, "include_empty" },
|
||||
{ "listreceivedbyaddress", 2, "include_watchonly" },
|
||||
{ "listreceivedbyaddress", 3, "address_filter" },
|
||||
{ "listreceivedbyaccount", 0, "minconf" },
|
||||
{ "listreceivedbyaccount", 1, "include_empty" },
|
||||
{ "listreceivedbyaccount", 2, "include_watchonly" },
|
||||
@@ -113,9 +112,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "walletcreatefundedpsbt", 0, "inputs" },
|
||||
{ "walletcreatefundedpsbt", 1, "outputs" },
|
||||
{ "walletcreatefundedpsbt", 2, "locktime" },
|
||||
{ "walletcreatefundedpsbt", 3, "replaceable" },
|
||||
{ "walletcreatefundedpsbt", 4, "options" },
|
||||
{ "walletcreatefundedpsbt", 5, "bip32derivs" },
|
||||
{ "walletcreatefundedpsbt", 3, "options" },
|
||||
{ "walletcreatefundedpsbt", 4, "bip32derivs" },
|
||||
{ "walletprocesspsbt", 1, "sign" },
|
||||
{ "walletprocesspsbt", 3, "bip32derivs" },
|
||||
{ "createpsbt", 0, "inputs" },
|
||||
|
||||
@@ -361,8 +361,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||
"}\n"
|
||||
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getblocktemplate", "")
|
||||
+ HelpExampleRpc("getblocktemplate", "")
|
||||
+ HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}")
|
||||
+ HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
@@ -474,7 +474,7 @@ static const CRPCCommand commands[] =
|
||||
{ "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
|
||||
{ "control", "logging", &logging, {"include", "exclude"}},
|
||||
{ "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */
|
||||
{ "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
|
||||
{ "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} },
|
||||
{ "util", "verifymessage", &verifymessage, {"address","signature","message"} },
|
||||
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
|
||||
|
||||
|
||||
@@ -436,7 +436,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
|
||||
}
|
||||
}
|
||||
|
||||
if (!rbf.isNull() && rbfOptIn != SignalsOptInRBF(rawTx)) {
|
||||
if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(rawTx)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
|
||||
}
|
||||
|
||||
@@ -1643,13 +1643,14 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
|
||||
}
|
||||
|
||||
// Get all of the previous transactions
|
||||
// Finalize input signatures -- in case we have partial signatures that add up to a complete
|
||||
// signature, but have not combined them yet (e.g. because the combiner that created this
|
||||
// PartiallySignedTransaction did not understand them), this will combine them into a final
|
||||
// script.
|
||||
bool complete = true;
|
||||
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
|
||||
PSBTInput& input = psbtx.inputs.at(i);
|
||||
|
||||
SignatureData sigdata;
|
||||
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, sigdata, i, 1);
|
||||
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, sigdata, i, SIGHASH_ALL);
|
||||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
@@ -1662,10 +1663,10 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
|
||||
mtx.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness;
|
||||
}
|
||||
ssTx << mtx;
|
||||
result.pushKV("hex", HexStr(ssTx.begin(), ssTx.end()));
|
||||
result.pushKV("hex", HexStr(ssTx.str()));
|
||||
} else {
|
||||
ssTx << psbtx;
|
||||
result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()));
|
||||
result.pushKV("psbt", EncodeBase64(ssTx.str()));
|
||||
}
|
||||
result.pushKV("complete", complete);
|
||||
|
||||
@@ -1777,7 +1778,7 @@ UniValue converttopsbt(const JSONRPCRequest& request)
|
||||
|
||||
// Remove all scriptSigs and scriptWitnesses from inputs
|
||||
for (CTxIn& input : tx.vin) {
|
||||
if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && (request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool()))) {
|
||||
if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && !permitsigdata) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Inputs must not have scriptSigs and scriptWitnesses");
|
||||
}
|
||||
input.scriptSig.clear();
|
||||
|
||||
@@ -22,55 +22,8 @@
|
||||
// they can be included inside by changing public keys to private keys (WIF
|
||||
// format), and changing xpubs by xprvs.
|
||||
//
|
||||
// 1. Examples
|
||||
//
|
||||
// A P2PK descriptor with a fixed public key:
|
||||
// - pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)
|
||||
//
|
||||
// A P2SH-P2WSH-P2PKH descriptor with a fixed public key:
|
||||
// - sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)))
|
||||
//
|
||||
// A bare 1-of-2 multisig descriptor:
|
||||
// - multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)
|
||||
//
|
||||
// A chain of P2PKH outputs (this needs the corresponding private key to derive):
|
||||
// - pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2/*)
|
||||
//
|
||||
// 2. Grammar description:
|
||||
//
|
||||
// X: xpub or xprv encoded extended key
|
||||
// I: decimal encoded integer
|
||||
// H: Hex encoded byte array
|
||||
// A: Address in P2PKH, P2SH, or Bech32 encoding
|
||||
//
|
||||
// S (Scripts):
|
||||
// * pk(P): Pay-to-pubkey (P2PK) output for public key P.
|
||||
// * pkh(P): Pay-to-pubkey-hash (P2PKH) output for public key P.
|
||||
// * wpkh(P): Pay-to-witness-pubkey-hash (P2WPKH) output for public key P.
|
||||
// * sh(S): Pay-to-script-hash (P2SH) output for script S
|
||||
// * wsh(S): Pay-to-witness-script-hash (P2WSH) output for script S
|
||||
// * combo(P): combination of P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH for public key P.
|
||||
// * multi(I,L): k-of-n multisig for given public keys
|
||||
// * addr(A): Output to address
|
||||
// * raw(H): scriptPubKey with raw bytes
|
||||
//
|
||||
// P (Public keys):
|
||||
// * H: fixed public key (or WIF-encoded private key)
|
||||
// * E: extended public key
|
||||
// * E/*: (ranged) all unhardened direct children of an extended public key
|
||||
// * E/*': (ranged) all hardened direct children of an extended public key
|
||||
//
|
||||
// L (Comma-separated lists of public keys):
|
||||
// * P
|
||||
// * L,P
|
||||
//
|
||||
// E (Extended public keys):
|
||||
// * X
|
||||
// * E/I: unhardened child
|
||||
// * E/I': hardened child
|
||||
// * E/Ih: hardened child (alternative notation)
|
||||
//
|
||||
// The top level is S.
|
||||
// Reference documentation about the descriptor language can be found in
|
||||
// doc/descriptors.md.
|
||||
|
||||
/** Interface for parsed descriptor objects. */
|
||||
struct Descriptor {
|
||||
|
||||
@@ -69,15 +69,15 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion)
|
||||
static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion)
|
||||
{
|
||||
CKeyID keyid = pubkey.GetID();
|
||||
const auto it = sigdata.signatures.find(keyid);
|
||||
if (it != sigdata.signatures.end()) {
|
||||
sig_out = it->second.second;
|
||||
return true;
|
||||
}
|
||||
CPubKey pubkey;
|
||||
GetPubKey(provider, sigdata, keyid, pubkey);
|
||||
sigdata.misc_pubkeys.emplace(keyid, pubkey);
|
||||
if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) {
|
||||
auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));
|
||||
assert(i.second);
|
||||
@@ -111,15 +111,15 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
||||
case TX_WITNESS_UNKNOWN:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false;
|
||||
if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false;
|
||||
ret.push_back(std::move(sig));
|
||||
return true;
|
||||
case TX_PUBKEYHASH: {
|
||||
CKeyID keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false;
|
||||
ret.push_back(std::move(sig));
|
||||
CPubKey pubkey;
|
||||
GetPubKey(provider, sigdata, keyID, pubkey);
|
||||
if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) return false;
|
||||
ret.push_back(std::move(sig));
|
||||
ret.push_back(ToByteVector(pubkey));
|
||||
return true;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
||||
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
|
||||
for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
|
||||
CPubKey pubkey = CPubKey(vSolutions[i]);
|
||||
if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) {
|
||||
if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) {
|
||||
ret.push_back(std::move(sig));
|
||||
}
|
||||
}
|
||||
@@ -233,10 +233,17 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
|
||||
return sigdata.complete;
|
||||
}
|
||||
|
||||
bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash)
|
||||
bool PSBTInputSigned(PSBTInput& input)
|
||||
{
|
||||
// if this input has a final scriptsig or scriptwitness, don't do anything with it
|
||||
if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
|
||||
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
|
||||
}
|
||||
|
||||
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, SignatureData& sigdata, int index, int sighash)
|
||||
{
|
||||
PSBTInput& input = psbt.inputs.at(index);
|
||||
const CMutableTransaction& tx = *psbt.tx;
|
||||
|
||||
if (PSBTInputSigned(input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -244,18 +251,45 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
|
||||
input.FillSignatureData(sigdata);
|
||||
|
||||
// Get UTXO
|
||||
bool require_witness_sig = false;
|
||||
CTxOut utxo;
|
||||
|
||||
// Verify input sanity, which checks that at most one of witness or non-witness utxos is provided.
|
||||
if (!input.IsSane()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.non_witness_utxo) {
|
||||
utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n];
|
||||
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
|
||||
COutPoint prevout = tx.vin[index].prevout;
|
||||
if (input.non_witness_utxo->GetHash() != prevout.hash) {
|
||||
return false;
|
||||
}
|
||||
utxo = input.non_witness_utxo->vout[prevout.n];
|
||||
} else if (!input.witness_utxo.IsNull()) {
|
||||
utxo = input.witness_utxo;
|
||||
// When we're taking our information from a witness UTXO, we can't verify it is actually data from
|
||||
// the output being spent. This is safe in case a witness signature is produced (which includes this
|
||||
// information directly in the hash), but not for non-witness signatures. Remember that we require
|
||||
// a witness signature in this situation.
|
||||
require_witness_sig = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash);
|
||||
sigdata.witness = false;
|
||||
bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
|
||||
// Verify that a witness signature was produced in case one was required.
|
||||
if (require_witness_sig && !sigdata.witness) return false;
|
||||
input.FromSignatureData(sigdata);
|
||||
|
||||
// If we have a witness signature, use the smaller witness UTXO.
|
||||
if (sigdata.witness) {
|
||||
input.witness_utxo = utxo;
|
||||
input.non_witness_utxo = nullptr;
|
||||
}
|
||||
|
||||
return sig_complete;
|
||||
}
|
||||
|
||||
@@ -475,6 +509,12 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
|
||||
return false;
|
||||
}
|
||||
|
||||
PartiallySignedTransaction::PartiallySignedTransaction(const CTransaction& tx) : tx(tx)
|
||||
{
|
||||
inputs.resize(tx.vin.size());
|
||||
outputs.resize(tx.vout.size());
|
||||
}
|
||||
|
||||
bool PartiallySignedTransaction::IsNull() const
|
||||
{
|
||||
return !tx && inputs.empty() && outputs.empty() && unknown.empty();
|
||||
|
||||
@@ -188,6 +188,9 @@ template<typename Stream>
|
||||
void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type)
|
||||
{
|
||||
for (auto keypath_pair : hd_keypaths) {
|
||||
if (!keypath_pair.first.IsValid()) {
|
||||
throw std::ios_base::failure("Invalid CPubKey being serialized");
|
||||
}
|
||||
SerializeToVector(s, type, MakeSpan(keypath_pair.first));
|
||||
WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t));
|
||||
for (auto& path : keypath_pair.second) {
|
||||
@@ -223,7 +226,8 @@ struct PSBTInput
|
||||
// If there is a non-witness utxo, then don't add the witness one.
|
||||
if (non_witness_utxo) {
|
||||
SerializeToVector(s, PSBT_IN_NON_WITNESS_UTXO);
|
||||
SerializeToVector(s, non_witness_utxo);
|
||||
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
SerializeToVector(os, non_witness_utxo);
|
||||
} else if (!witness_utxo.IsNull()) {
|
||||
SerializeToVector(s, PSBT_IN_WITNESS_UTXO);
|
||||
SerializeToVector(s, witness_utxo);
|
||||
@@ -282,6 +286,7 @@ struct PSBTInput
|
||||
template <typename Stream>
|
||||
inline void Unserialize(Stream& s) {
|
||||
// Read loop
|
||||
bool found_sep = false;
|
||||
while(!s.empty()) {
|
||||
// Read
|
||||
std::vector<unsigned char> key;
|
||||
@@ -289,7 +294,10 @@ struct PSBTInput
|
||||
|
||||
// the key is empty if that was actually a separator byte
|
||||
// This is a special case for key lengths 0 as those are not allowed (except for separator)
|
||||
if (key.empty()) return;
|
||||
if (key.empty()) {
|
||||
found_sep = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// First byte of key is the type
|
||||
unsigned char type = key[0];
|
||||
@@ -297,13 +305,17 @@ struct PSBTInput
|
||||
// Do stuff based on type
|
||||
switch(type) {
|
||||
case PSBT_IN_NON_WITNESS_UTXO:
|
||||
{
|
||||
if (non_witness_utxo) {
|
||||
throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided");
|
||||
} else if (key.size() != 1) {
|
||||
throw std::ios_base::failure("Non-witness utxo key is more than one byte type");
|
||||
}
|
||||
UnserializeFromVector(s, non_witness_utxo);
|
||||
// Set the stream to unserialize with witness since this is always a valid network transaction
|
||||
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() & ~SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
UnserializeFromVector(os, non_witness_utxo);
|
||||
break;
|
||||
}
|
||||
case PSBT_IN_WITNESS_UTXO:
|
||||
if (!witness_utxo.IsNull()) {
|
||||
throw std::ios_base::failure("Duplicate Key, input witness utxo already provided");
|
||||
@@ -400,6 +412,10 @@ struct PSBTInput
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_sep) {
|
||||
throw std::ios_base::failure("Separator is missing at the end of an input map");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
@@ -453,6 +469,7 @@ struct PSBTOutput
|
||||
template <typename Stream>
|
||||
inline void Unserialize(Stream& s) {
|
||||
// Read loop
|
||||
bool found_sep = false;
|
||||
while(!s.empty()) {
|
||||
// Read
|
||||
std::vector<unsigned char> key;
|
||||
@@ -460,7 +477,10 @@ struct PSBTOutput
|
||||
|
||||
// the key is empty if that was actually a separator byte
|
||||
// This is a special case for key lengths 0 as those are not allowed (except for separator)
|
||||
if (key.empty()) return;
|
||||
if (key.empty()) {
|
||||
found_sep = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// First byte of key is the type
|
||||
unsigned char type = key[0];
|
||||
@@ -505,6 +525,10 @@ struct PSBTOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_sep) {
|
||||
throw std::ios_base::failure("Separator is missing at the end of an output map");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
@@ -526,6 +550,7 @@ struct PartiallySignedTransaction
|
||||
bool IsSane() const;
|
||||
PartiallySignedTransaction() {}
|
||||
PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {}
|
||||
explicit PartiallySignedTransaction(const CTransaction& tx);
|
||||
|
||||
// Only checks if they refer to the same transaction
|
||||
friend bool operator==(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b)
|
||||
@@ -547,7 +572,8 @@ struct PartiallySignedTransaction
|
||||
SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX);
|
||||
|
||||
// Write serialized tx to a stream
|
||||
SerializeToVector(s, *tx);
|
||||
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
SerializeToVector(os, *tx);
|
||||
|
||||
// Write the unknown things
|
||||
for (auto& entry : unknown) {
|
||||
@@ -579,6 +605,7 @@ struct PartiallySignedTransaction
|
||||
}
|
||||
|
||||
// Read global data
|
||||
bool found_sep = false;
|
||||
while(!s.empty()) {
|
||||
// Read
|
||||
std::vector<unsigned char> key;
|
||||
@@ -586,7 +613,10 @@ struct PartiallySignedTransaction
|
||||
|
||||
// the key is empty if that was actually a separator byte
|
||||
// This is a special case for key lengths 0 as those are not allowed (except for separator)
|
||||
if (key.empty()) break;
|
||||
if (key.empty()) {
|
||||
found_sep = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// First byte of key is the type
|
||||
unsigned char type = key[0];
|
||||
@@ -601,7 +631,9 @@ struct PartiallySignedTransaction
|
||||
throw std::ios_base::failure("Global unsigned tx key is more than one byte type");
|
||||
}
|
||||
CMutableTransaction mtx;
|
||||
UnserializeFromVector(s, mtx);
|
||||
// Set the stream to serialize with non-witness since this should always be non-witness
|
||||
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
UnserializeFromVector(os, mtx);
|
||||
tx = std::move(mtx);
|
||||
// Make sure that all scriptSigs and scriptWitnesses are empty
|
||||
for (const CTxIn& txin : tx->vin) {
|
||||
@@ -624,6 +656,10 @@ struct PartiallySignedTransaction
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_sep) {
|
||||
throw std::ios_base::failure("Separator is missing at the end of the global map");
|
||||
}
|
||||
|
||||
// Make sure that we got an unsigned tx
|
||||
if (!tx) {
|
||||
throw std::ios_base::failure("No unsigned transcation was provided");
|
||||
@@ -678,8 +714,11 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
|
||||
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
|
||||
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
|
||||
/** Signs a PSBTInput */
|
||||
bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1);
|
||||
/** Checks whether a PSBTInput is already signed. */
|
||||
bool PSBTInputSigned(PSBTInput& input);
|
||||
|
||||
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
|
||||
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, SignatureData& sigdata, int index, int sighash = SIGHASH_ALL);
|
||||
|
||||
/** Extract signature data from a transaction input, and insert it. */
|
||||
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
|
||||
int GetVersion() const { return nVersion; }
|
||||
int GetType() const { return nType; }
|
||||
size_t size() const { return stream->size(); }
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
|
||||
@@ -344,4 +344,49 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
|
||||
BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {
|
||||
// Check that the highest legal index is decoded correctly
|
||||
BlockTransactionsRequest req0;
|
||||
req0.blockhash = InsecureRand256();
|
||||
req0.indexes.resize(1);
|
||||
req0.indexes[0] = 0xffff;
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << req0;
|
||||
|
||||
BlockTransactionsRequest req1;
|
||||
stream >> req1;
|
||||
BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size());
|
||||
BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
|
||||
// Any set of index deltas that starts with N values that sum to (0x10000 - N)
|
||||
// causes the edge-case overflow that was originally not checked for. Such
|
||||
// a request cannot be created by serializing a real BlockTransactionsRequest
|
||||
// due to the overflow, so here we'll serialize from raw deltas.
|
||||
BlockTransactionsRequest req0;
|
||||
req0.blockhash = InsecureRand256();
|
||||
req0.indexes.resize(3);
|
||||
req0.indexes[0] = 0x7000;
|
||||
req0.indexes[1] = 0x10000 - 0x7000 - 2;
|
||||
req0.indexes[2] = 0;
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << req0.blockhash;
|
||||
WriteCompactSize(stream, req0.indexes.size());
|
||||
WriteCompactSize(stream, req0.indexes[0]);
|
||||
WriteCompactSize(stream, req0.indexes[1]);
|
||||
WriteCompactSize(stream, req0.indexes[2]);
|
||||
|
||||
BlockTransactionsRequest req1;
|
||||
try {
|
||||
stream >> req1;
|
||||
// before patch: deserialize above succeeds and this check fails, demonstrating the overflow
|
||||
BOOST_CHECK(req1.indexes[1] < req1.indexes[2]);
|
||||
// this shouldn't be reachable before or after patch
|
||||
BOOST_CHECK(0);
|
||||
} catch(std::ios_base::failure &) {
|
||||
// deserialize should fail
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -189,4 +189,42 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
BOOST_CHECK(pnode2->fFeeler == false);
|
||||
}
|
||||
|
||||
// prior to PR #14728, this test triggers an undefined behavior
|
||||
BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
||||
{
|
||||
// set up local addresses; all that's necessary to reproduce the bug is
|
||||
// that a normal IPv4 address is among the entries, but if this address is
|
||||
// !IsRoutable the undefined behavior is easier to trigger deterministically
|
||||
{
|
||||
LOCK(cs_mapLocalHost);
|
||||
in_addr ipv4AddrLocal;
|
||||
ipv4AddrLocal.s_addr = 0x0100007f;
|
||||
CNetAddr addr = CNetAddr(ipv4AddrLocal);
|
||||
LocalServiceInfo lsi;
|
||||
lsi.nScore = 23;
|
||||
lsi.nPort = 42;
|
||||
mapLocalHost[addr] = lsi;
|
||||
}
|
||||
|
||||
// create a peer with an IPv4 address
|
||||
in_addr ipv4AddrPeer;
|
||||
ipv4AddrPeer.s_addr = 0xa0b0c001;
|
||||
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
|
||||
std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, false);
|
||||
pnode->fSuccessfullyConnected.store(true);
|
||||
|
||||
// the peer claims to be reaching us via IPv6
|
||||
in6_addr ipv6AddrLocal;
|
||||
memset(ipv6AddrLocal.s6_addr, 0, 16);
|
||||
ipv6AddrLocal.s6_addr[0] = 0xcc;
|
||||
CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
|
||||
pnode->SetAddrLocal(addrLocal);
|
||||
|
||||
// before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
|
||||
AdvertiseLocal(&*pnode);
|
||||
|
||||
// suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
|
||||
BOOST_CHECK(1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -138,11 +138,11 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
|
||||
// the callbacks should run in exactly the order in which they were enqueued
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
queue1.AddToProcessQueue([i, &counter1]() {
|
||||
BOOST_CHECK_EQUAL(i, counter1++);
|
||||
assert(i == counter1++);
|
||||
});
|
||||
|
||||
queue2.AddToProcessQueue([i, &counter2]() {
|
||||
BOOST_CHECK_EQUAL(i, counter2++);
|
||||
assert(i == counter2++);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
|
||||
BOOST_ERROR("Read incorrect tx");
|
||||
}
|
||||
}
|
||||
|
||||
txindex.Stop(); // Stop thread before calling destructor
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
23
src/util.cpp
23
src/util.cpp
@@ -820,11 +820,11 @@ static std::string TrimString(const std::string& str, const std::string& pattern
|
||||
return str.substr(front, end - front + 1);
|
||||
}
|
||||
|
||||
static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::istream& stream)
|
||||
static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>> &options)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> options;
|
||||
std::string str, prefix;
|
||||
std::string::size_type pos;
|
||||
int linenr = 1;
|
||||
while (std::getline(stream, str)) {
|
||||
if ((pos = str.find('#')) != std::string::npos) {
|
||||
str = str.substr(0, pos);
|
||||
@@ -834,21 +834,34 @@ static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::is
|
||||
if (!str.empty()) {
|
||||
if (*str.begin() == '[' && *str.rbegin() == ']') {
|
||||
prefix = str.substr(1, str.size() - 2) + '.';
|
||||
} else if (*str.begin() == '-') {
|
||||
error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
|
||||
return false;
|
||||
} else if ((pos = str.find('=')) != std::string::npos) {
|
||||
std::string name = prefix + TrimString(str.substr(0, pos), pattern);
|
||||
std::string value = TrimString(str.substr(pos + 1), pattern);
|
||||
options.emplace_back(name, value);
|
||||
} else {
|
||||
error = strprintf("parse error on line %i: %s", linenr, str);
|
||||
if (str.size() >= 2 && str.substr(0, 2) == "no") {
|
||||
error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++linenr;
|
||||
}
|
||||
return options;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys)
|
||||
{
|
||||
LOCK(cs_args);
|
||||
|
||||
for (const std::pair<std::string, std::string>& option : GetConfigOptions(stream)) {
|
||||
std::vector<std::pair<std::string, std::string>> options;
|
||||
if (!GetConfigOptions(stream, error, options)) {
|
||||
return false;
|
||||
}
|
||||
for (const std::pair<std::string, std::string>& option : options) {
|
||||
std::string strKey = std::string("-") + option.first;
|
||||
std::string strValue = option.second;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ static const std::string SAFE_CHARS[] =
|
||||
CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
|
||||
CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
|
||||
CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
|
||||
CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
|
||||
};
|
||||
|
||||
std::string SanitizeString(const std::string& str, int rule)
|
||||
|
||||
@@ -25,6 +25,7 @@ enum SafeChars
|
||||
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
|
||||
SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset
|
||||
SAFE_CHARS_FILENAME, //!< Chars allowed in filenames
|
||||
SAFE_CHARS_URI, //!< Chars allowed in URIs (RFC 3986)
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -3130,7 +3130,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
||||
|
||||
// Check transactions
|
||||
for (const auto& tx : block.vtx)
|
||||
if (!CheckTransaction(*tx, state, false))
|
||||
if (!CheckTransaction(*tx, state, true))
|
||||
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
|
||||
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
|
||||
|
||||
|
||||
@@ -1805,9 +1805,14 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const
|
||||
bool fAllAccounts = (strAccount == std::string("*"));
|
||||
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
|
||||
|
||||
bool list_sent = fAllAccounts;
|
||||
|
||||
if (IsDeprecatedRPCEnabled("accounts")) {
|
||||
list_sent |= strAccount == strSentAccount;
|
||||
}
|
||||
|
||||
// Sent
|
||||
if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
|
||||
{
|
||||
if (list_sent) {
|
||||
for (const COutputEntry& s : listSent)
|
||||
{
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
@@ -1901,12 +1906,14 @@ UniValue listtransactions(const JSONRPCRequest& request)
|
||||
|
||||
std::string help_text {};
|
||||
if (!IsDeprecatedRPCEnabled("accounts")) {
|
||||
help_text = "listtransactions (dummy count skip include_watchonly)\n"
|
||||
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
|
||||
help_text = "listtransactions (label count skip include_watchonly)\n"
|
||||
"\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
|
||||
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n"
|
||||
"Note that the \"account\" argument and \"otheraccount\" return value have been removed in V0.17. To use this RPC with an \"account\" argument, restart\n"
|
||||
"bitcoind with -deprecatedrpc=accounts\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"dummy\" (string, optional) If set, should be \"*\" for backwards compatibility.\n"
|
||||
"1. \"label\" (string, optional) If set, should be a valid label name to return only incoming transactions\n"
|
||||
" with the specified label, or \"*\" to disable filtering and return all transactions.\n"
|
||||
"2. count (numeric, optional, default=10) The number of transactions to return\n"
|
||||
"3. skip (numeric, optional, default=0) The number of transactions to skip\n"
|
||||
"4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
|
||||
@@ -2012,8 +2019,8 @@ UniValue listtransactions(const JSONRPCRequest& request)
|
||||
std::string strAccount = "*";
|
||||
if (!request.params[0].isNull()) {
|
||||
strAccount = request.params[0].get_str();
|
||||
if (!IsDeprecatedRPCEnabled("accounts") && strAccount != "*") {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
|
||||
if (!IsDeprecatedRPCEnabled("accounts") && strAccount.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
|
||||
}
|
||||
}
|
||||
int nCount = 10;
|
||||
@@ -2539,13 +2546,6 @@ static UniValue keypoolrefill(const JSONRPCRequest& request)
|
||||
}
|
||||
|
||||
|
||||
static void LockWallet(CWallet* pWallet)
|
||||
{
|
||||
LOCK(pWallet->cs_wallet);
|
||||
pWallet->nRelockTime = 0;
|
||||
pWallet->Lock();
|
||||
}
|
||||
|
||||
static UniValue walletpassphrase(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
@@ -2615,7 +2615,18 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
|
||||
pwallet->TopUpKeyPool();
|
||||
|
||||
pwallet->nRelockTime = GetTime() + nSleepTime;
|
||||
RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), std::bind(LockWallet, pwallet), nSleepTime);
|
||||
|
||||
// Keep a weak pointer to the wallet so that it is possible to unload the
|
||||
// wallet before the following callback is called. If a valid shared pointer
|
||||
// is acquired in the callback then the wallet is still loaded.
|
||||
std::weak_ptr<CWallet> weak_wallet = wallet;
|
||||
RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet] {
|
||||
if (auto shared_wallet = weak_wallet.lock()) {
|
||||
LOCK(shared_wallet->cs_wallet);
|
||||
shared_wallet->Lock();
|
||||
shared_wallet->nRelockTime = 0;
|
||||
}
|
||||
}, nSleepTime);
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
@@ -3725,6 +3736,8 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
|
||||
|
||||
// Sign the transaction
|
||||
LOCK2(cs_main, pwallet->cs_wallet);
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]);
|
||||
}
|
||||
|
||||
@@ -4493,23 +4506,34 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubK
|
||||
hd_keypaths.emplace(vchPubKey, keypath);
|
||||
}
|
||||
|
||||
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs)
|
||||
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, int sighash_type, bool sign, bool bip32derivs)
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
// Get all of the previous transactions
|
||||
bool complete = true;
|
||||
for (unsigned int i = 0; i < txConst->vin.size(); ++i) {
|
||||
const CTxIn& txin = txConst->vin[i];
|
||||
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
|
||||
const CTxIn& txin = psbtx.tx->vin[i];
|
||||
PSBTInput& input = psbtx.inputs.at(i);
|
||||
|
||||
// If we don't know about this input, skip it and let someone else deal with it
|
||||
const uint256& txhash = txin.prevout.hash;
|
||||
const auto& it = pwallet->mapWallet.find(txhash);
|
||||
if (it != pwallet->mapWallet.end()) {
|
||||
const CWalletTx& wtx = it->second;
|
||||
CTxOut utxo = wtx.tx->vout[txin.prevout.n];
|
||||
input.non_witness_utxo = wtx.tx;
|
||||
input.witness_utxo = utxo;
|
||||
if (PSBTInputSigned(input)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify input looks sane. This will check that we have at most one uxto, witness or non-witness.
|
||||
if (!input.IsSane()) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "PSBT input is not sane.");
|
||||
}
|
||||
|
||||
// If we have no utxo, grab it from the wallet.
|
||||
if (!input.non_witness_utxo && input.witness_utxo.IsNull()) {
|
||||
const uint256& txhash = txin.prevout.hash;
|
||||
const auto it = pwallet->mapWallet.find(txhash);
|
||||
if (it != pwallet->mapWallet.end()) {
|
||||
const CWalletTx& wtx = it->second;
|
||||
// We only need the non_witness_utxo, which is a superset of the witness_utxo.
|
||||
// The signing code will switch to the smaller witness_utxo if this is ok.
|
||||
input.non_witness_utxo = wtx.tx;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the Sighash type
|
||||
@@ -4519,16 +4543,16 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
|
||||
|
||||
SignatureData sigdata;
|
||||
if (sign) {
|
||||
complete &= SignPSBTInput(*pwallet, *psbtx.tx, input, sigdata, i, sighash_type);
|
||||
complete &= SignPSBTInput(*pwallet, psbtx, sigdata, i, sighash_type);
|
||||
} else {
|
||||
complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type);
|
||||
complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), psbtx, sigdata, i, sighash_type);
|
||||
}
|
||||
|
||||
// Drop the unnecessary UTXO
|
||||
if (sigdata.witness) {
|
||||
input.non_witness_utxo = nullptr;
|
||||
} else {
|
||||
input.witness_utxo.SetNull();
|
||||
// Convert the non-witness utxo to witness
|
||||
if (input.witness_utxo.IsNull() && input.non_witness_utxo) {
|
||||
input.witness_utxo = input.non_witness_utxo->vout[txin.prevout.n];
|
||||
}
|
||||
}
|
||||
|
||||
// Get public key paths
|
||||
@@ -4540,8 +4564,8 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
|
||||
}
|
||||
|
||||
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
|
||||
for (unsigned int i = 0; i < txConst->vout.size(); ++i) {
|
||||
const CTxOut& out = txConst->vout.at(i);
|
||||
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
|
||||
const CTxOut& out = psbtx.tx->vout.at(i);
|
||||
PSBTOutput& psbt_out = psbtx.outputs.at(i);
|
||||
|
||||
// Dummy tx so we can use ProduceSignature to get stuff out
|
||||
@@ -4593,7 +4617,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
|
||||
" \"ALL|ANYONECANPAY\"\n"
|
||||
" \"NONE|ANYONECANPAY\"\n"
|
||||
" \"SINGLE|ANYONECANPAY\"\n"
|
||||
"4. bip32derivs (boolean, optiona, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
|
||||
"4. bip32derivs (boolean, optional, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
|
||||
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
@@ -4618,19 +4642,15 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
|
||||
// Get the sighash type
|
||||
int nHashType = ParseSighashString(request.params[2]);
|
||||
|
||||
// Use CTransaction for the constant parts of the
|
||||
// transaction to avoid rehashing.
|
||||
const CTransaction txConst(*psbtx.tx);
|
||||
|
||||
// Fill transaction with our data and also sign
|
||||
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
|
||||
bool bip32derivs = request.params[3].isNull() ? false : request.params[3].get_bool();
|
||||
bool complete = FillPSBT(pwallet, psbtx, &txConst, nHashType, sign, bip32derivs);
|
||||
bool complete = FillPSBT(pwallet, psbtx, nHashType, sign, bip32derivs);
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << psbtx;
|
||||
result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()));
|
||||
result.pushKV("psbt", EncodeBase64(ssTx.str()));
|
||||
result.pushKV("complete", complete);
|
||||
|
||||
return result;
|
||||
@@ -4645,7 +4665,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 6)
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
|
||||
throw std::runtime_error(
|
||||
"walletcreatefundedpsbt [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable ) ( options bip32derivs )\n"
|
||||
"\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n"
|
||||
@@ -4672,9 +4692,8 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
|
||||
" accepted as second parameter.\n"
|
||||
" ]\n"
|
||||
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
|
||||
"4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
|
||||
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
|
||||
"5. options (object, optional)\n"
|
||||
"4. options (object, optional)\n"
|
||||
" {\n"
|
||||
" \"changeAddress\" (string, optional, default pool address) The bitcoin address to receive the change\n"
|
||||
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
|
||||
@@ -4696,7 +4715,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
|
||||
" \"ECONOMICAL\"\n"
|
||||
" \"CONSERVATIVE\"\n"
|
||||
" }\n"
|
||||
"6. bip32derivs (boolean, optiona, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
|
||||
"5. bip32derivs (boolean, optional, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n"
|
||||
@@ -4712,40 +4731,29 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
|
||||
UniValue::VARR,
|
||||
UniValueType(), // ARR or OBJ, checked later
|
||||
UniValue::VNUM,
|
||||
UniValue::VBOOL,
|
||||
UniValue::VOBJ
|
||||
UniValue::VOBJ,
|
||||
UniValue::VBOOL
|
||||
}, true
|
||||
);
|
||||
|
||||
CAmount fee;
|
||||
int change_position;
|
||||
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]);
|
||||
FundTransaction(pwallet, rawTx, fee, change_position, request.params[4]);
|
||||
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]["replaceable"]);
|
||||
FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]);
|
||||
|
||||
// Make a blank psbt
|
||||
PartiallySignedTransaction psbtx;
|
||||
psbtx.tx = rawTx;
|
||||
for (unsigned int i = 0; i < rawTx.vin.size(); ++i) {
|
||||
psbtx.inputs.push_back(PSBTInput());
|
||||
}
|
||||
for (unsigned int i = 0; i < rawTx.vout.size(); ++i) {
|
||||
psbtx.outputs.push_back(PSBTOutput());
|
||||
}
|
||||
|
||||
// Use CTransaction for the constant parts of the
|
||||
// transaction to avoid rehashing.
|
||||
const CTransaction txConst(*psbtx.tx);
|
||||
PartiallySignedTransaction psbtx(rawTx);
|
||||
|
||||
// Fill transaction with out data but don't sign
|
||||
bool bip32derivs = request.params[5].isNull() ? false : request.params[5].get_bool();
|
||||
FillPSBT(pwallet, psbtx, &txConst, 1, false, bip32derivs);
|
||||
bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool();
|
||||
FillPSBT(pwallet, psbtx, 1, false, bip32derivs);
|
||||
|
||||
// Serialize the PSBT
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << psbtx;
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()));
|
||||
result.pushKV("psbt", EncodeBase64(ssTx.str()));
|
||||
result.pushKV("fee", ValueFromAmount(fee));
|
||||
result.pushKV("changepos", change_position);
|
||||
return result;
|
||||
@@ -4768,7 +4776,7 @@ static const CRPCCommand commands[] =
|
||||
// --------------------- ------------------------ ----------------------- ----------
|
||||
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
|
||||
{ "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} },
|
||||
{ "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","replaceable","options","bip32derivs"} },
|
||||
{ "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} },
|
||||
{ "hidden", "resendwallettransactions", &resendwallettransactions, {} },
|
||||
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
|
||||
{ "wallet", "abortrescan", &abortrescan, {} },
|
||||
@@ -4799,7 +4807,7 @@ static const CRPCCommand commands[] =
|
||||
{ "wallet", "listlockunspent", &listlockunspent, {} },
|
||||
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
|
||||
{ "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
|
||||
{ "wallet", "listtransactions", &listtransactions, {"account|dummy","count","skip","include_watchonly"} },
|
||||
{ "wallet", "listtransactions", &listtransactions, {"account|label|dummy","count","skip","include_watchonly"} },
|
||||
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
|
||||
{ "wallet", "listwallets", &listwallets, {} },
|
||||
{ "wallet", "loadwallet", &loadwallet, {"filename"} },
|
||||
|
||||
@@ -30,5 +30,5 @@ bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
|
||||
|
||||
UniValue getaddressinfo(const JSONRPCRequest& request);
|
||||
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);
|
||||
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type = 1, bool sign = true, bool bip32derivs = false);
|
||||
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false);
|
||||
#endif //BITCOIN_WALLET_RPCWALLET_H
|
||||
|
||||
@@ -59,12 +59,8 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
|
||||
CDataStream ssData(ParseHex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssData >> psbtx;
|
||||
|
||||
// Use CTransaction for the constant parts of the
|
||||
// transaction to avoid rehashing.
|
||||
const CTransaction txConst(*psbtx.tx);
|
||||
|
||||
// Fill transaction with our data
|
||||
FillPSBT(&m_wallet, psbtx, &txConst, 1, false, true);
|
||||
FillPSBT(&m_wallet, psbtx, SIGHASH_ALL, false, true);
|
||||
|
||||
// Get the final tx
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <validation.h>
|
||||
#include <wallet/coincontrol.h>
|
||||
#include <wallet/test/wallet_test_fixture.h>
|
||||
#include <policy/policy.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <univalue.h>
|
||||
@@ -374,4 +375,47 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
|
||||
BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false));
|
||||
}
|
||||
|
||||
// Explicit calculation which is used to test the wallet constant
|
||||
// We get the same virtual size due to rounding(weight/4) for both use_max_sig values
|
||||
static size_t CalculateNestedKeyhashInputSize(bool use_max_sig)
|
||||
{
|
||||
// Generate ephemeral valid pubkey
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
|
||||
// Generate pubkey hash
|
||||
uint160 key_hash(Hash160(pubkey.begin(), pubkey.end()));
|
||||
|
||||
// Create inner-script to enter into keystore. Key hash can't be 0...
|
||||
CScript inner_script = CScript() << OP_0 << std::vector<unsigned char>(key_hash.begin(), key_hash.end());
|
||||
|
||||
// Create outer P2SH script for the output
|
||||
uint160 script_id(Hash160(inner_script.begin(), inner_script.end()));
|
||||
CScript script_pubkey = CScript() << OP_HASH160 << std::vector<unsigned char>(script_id.begin(), script_id.end()) << OP_EQUAL;
|
||||
|
||||
// Add inner-script to key store and key to watchonly
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddCScript(inner_script);
|
||||
keystore.AddKeyPubKey(key, pubkey);
|
||||
|
||||
// Fill in dummy signatures for fee calculation.
|
||||
SignatureData sig_data;
|
||||
|
||||
if (!ProduceSignature(keystore, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, script_pubkey, sig_data)) {
|
||||
// We're hand-feeding it correct arguments; shouldn't happen
|
||||
assert(false);
|
||||
}
|
||||
|
||||
CTxIn tx_in;
|
||||
UpdateInput(tx_in, sig_data);
|
||||
return (size_t)GetVirtualTransactionInputSize(tx_in);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(dummy_input_size_test, TestChain100Setup)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(false), DUMMY_NESTED_P2WPKH_INPUT_SIZE);
|
||||
BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(true), DUMMY_NESTED_P2WPKH_INPUT_SIZE);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -1607,8 +1607,6 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet,
|
||||
CMutableTransaction txn;
|
||||
txn.vin.push_back(CTxIn(COutPoint()));
|
||||
if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) {
|
||||
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
|
||||
// implies that we can sign for every input.
|
||||
return -1;
|
||||
}
|
||||
return GetVirtualTransactionInputSize(txn.vin[0]);
|
||||
@@ -2832,7 +2830,14 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
|
||||
if (pick_new_inputs) {
|
||||
nValueIn = 0;
|
||||
setCoins.clear();
|
||||
coin_selection_params.change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, this);
|
||||
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;
|
||||
}
|
||||
coin_selection_params.effective_fee = nFeeRateNeeded;
|
||||
if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coin_control, coin_selection_params, bnb_used))
|
||||
{
|
||||
@@ -2846,6 +2851,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bnb_used = false;
|
||||
}
|
||||
|
||||
const CAmount nChange = nValueIn - nValueToSelect;
|
||||
|
||||
@@ -64,6 +64,9 @@ static const bool DEFAULT_WALLET_RBF = false;
|
||||
static const bool DEFAULT_WALLETBROADCAST = true;
|
||||
static const bool DEFAULT_DISABLE_WALLET = false;
|
||||
|
||||
//! Pre-calculated constants for input size estimation in *virtual size*
|
||||
static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;
|
||||
|
||||
class CBlockIndex;
|
||||
class CCoinControl;
|
||||
class COutput;
|
||||
|
||||
@@ -17,14 +17,16 @@
|
||||
"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"
|
||||
],
|
||||
"valid" : [
|
||||
"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"
|
||||
],
|
||||
"creator" : [
|
||||
{
|
||||
@@ -57,15 +59,62 @@
|
||||
],
|
||||
"psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
|
||||
},
|
||||
{
|
||||
"privkeys" : [
|
||||
"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
|
||||
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
|
||||
],
|
||||
"psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
|
||||
},
|
||||
{
|
||||
"privkeys" : [
|
||||
"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
|
||||
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
|
||||
],
|
||||
"psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
|
||||
},
|
||||
{
|
||||
"privkeys" : [
|
||||
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
|
||||
],
|
||||
"psbt" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=",
|
||||
"result" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
||||
},
|
||||
{
|
||||
"privkeys" : [
|
||||
"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
|
||||
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
|
||||
],
|
||||
"psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
|
||||
},
|
||||
{
|
||||
"privkeys" : [
|
||||
"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
|
||||
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
|
||||
],
|
||||
"psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
|
||||
},
|
||||
{
|
||||
"privkeys" : [
|
||||
"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
|
||||
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
|
||||
],
|
||||
"psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
|
||||
}
|
||||
],
|
||||
"combiner" : [
|
||||
{
|
||||
"combine" : [
|
||||
"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"
|
||||
],
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"
|
||||
"result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXRzBEAiBjGpif5zipKtAZhgIzEsGSFP4oArOeXLwaw2eIBsaSwwIgOdtsOHvSZ3Ft/bPU2NpQuOhdITMmunx9qqTAzkHrkiMBAQMEAQAAAAEER1IhApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/IQLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU211KuIgYClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8Q2QxqTwAAAIAAAACAAAAAgCIGAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXENkMak8AAACAAAAAgAEAAIAAAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IciAgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3EcwRAIgYut6VWEHp8c/RaxKtaHd329wdfsSdZaafzg+//eEvLICIAwF27dHDb8vCFV901bHMlwe0wkT6ZbNOECUXbEiKNpfASICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
|
||||
},
|
||||
{
|
||||
"combine" : [
|
||||
|
||||
@@ -15,8 +15,8 @@ from collections import defaultdict
|
||||
|
||||
# Avoid wildcard * imports if possible
|
||||
from test_framework.blocktools import (create_block, create_coinbase)
|
||||
from test_framework.messages import CInv
|
||||
from test_framework.mininode import (
|
||||
CInv,
|
||||
P2PInterface,
|
||||
mininode_lock,
|
||||
msg_block,
|
||||
@@ -67,10 +67,11 @@ def custom_function():
|
||||
# self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
|
||||
pass
|
||||
|
||||
|
||||
class ExampleTest(BitcoinTestFramework):
|
||||
# Each functional test is a subclass of the BitcoinTestFramework class.
|
||||
|
||||
# Override the set_test_params(), add_options(), setup_chain(), setup_network()
|
||||
# Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network()
|
||||
# and setup_nodes() methods to customize the test setup as required.
|
||||
|
||||
def set_test_params(self):
|
||||
@@ -84,6 +85,9 @@ class ExampleTest(BitcoinTestFramework):
|
||||
|
||||
# self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test()
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
# Use add_options() to add specific command-line options for your test.
|
||||
# In practice this is not used very much, since the tests are mostly written
|
||||
# to be run in automated environments without command-line options.
|
||||
@@ -111,7 +115,7 @@ class ExampleTest(BitcoinTestFramework):
|
||||
# sync_all() should not include node2, since we're not expecting it to
|
||||
# sync.
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
self.sync_all([self.nodes[0:1]])
|
||||
self.sync_all([self.nodes[0:2]])
|
||||
|
||||
# Use setup_nodes() to customize the node start behaviour (for example if
|
||||
# you don't want to start all nodes at the start of the test).
|
||||
@@ -135,7 +139,7 @@ class ExampleTest(BitcoinTestFramework):
|
||||
|
||||
# Generating a block on one of the nodes will get us out of IBD
|
||||
blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
|
||||
self.sync_all([self.nodes[0:1]])
|
||||
self.sync_all([self.nodes[0:2]])
|
||||
|
||||
# Notice above how we called an RPC by calling a method with the same
|
||||
# name on the node object. Notice also how we used a keyword argument
|
||||
|
||||
@@ -25,6 +25,9 @@ class BIP68Test(BitcoinTestFramework):
|
||||
self.num_nodes = 2
|
||||
self.extra_args = [[], ["-acceptnonstdtxn=0"]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.extra_args = [[]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
node = self.nodes[0] # convenience reference to the node
|
||||
|
||||
@@ -169,7 +172,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Reject a block where the miner creates too much coinbase reward")
|
||||
self.move_tip(6)
|
||||
b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
|
||||
self.sync_blocks([b9], False, 16, b'bad-cb-amount', reconnect=True)
|
||||
self.sync_blocks([b9], success=False, reject_code=16, reject_reason=b'bad-cb-amount', reconnect=True)
|
||||
|
||||
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -181,7 +184,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.sync_blocks([b10], False)
|
||||
|
||||
b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
|
||||
self.sync_blocks([b11], False, 16, b'bad-cb-amount', reconnect=True)
|
||||
self.sync_blocks([b11], success=False, reject_code=16, reject_reason=b'bad-cb-amount', reconnect=True)
|
||||
|
||||
# Try again, but with a valid fork first
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -194,7 +197,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b13 = self.next_block(13, spend=out[4])
|
||||
self.save_spendable_output()
|
||||
b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
|
||||
self.sync_blocks([b12, b13, b14], False, 16, b'bad-cb-amount', reconnect=True)
|
||||
self.sync_blocks([b12, b13, b14], success=False, reject_code=16, reject_reason=b'bad-cb-amount', reconnect=True)
|
||||
|
||||
# New tip should be b13.
|
||||
assert_equal(node.getbestblockhash(), b13.hash)
|
||||
@@ -213,7 +216,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Reject a block with too many checksigs")
|
||||
too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
|
||||
b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
|
||||
self.sync_blocks([b16], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b16], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
# Attempt to spend a transaction created on a different fork
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -222,7 +225,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Reject a block with a spend from a re-org'ed out tx")
|
||||
self.move_tip(15)
|
||||
b17 = self.next_block(17, spend=txout_b3)
|
||||
self.sync_blocks([b17], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b17], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# Attempt to spend a transaction created on a different fork (on a fork this time)
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -235,7 +238,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.sync_blocks([b18], False)
|
||||
|
||||
b19 = self.next_block(19, spend=out[6])
|
||||
self.sync_blocks([b19], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b19], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# Attempt to spend a coinbase at depth too low
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -244,7 +247,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Reject a block spending an immature coinbase.")
|
||||
self.move_tip(15)
|
||||
b20 = self.next_block(20, spend=out[7])
|
||||
self.sync_blocks([b20], False, 16, b'bad-txns-premature-spend-of-coinbase')
|
||||
self.sync_blocks([b20], success=False, reject_code=16, reject_reason=b'bad-txns-premature-spend-of-coinbase')
|
||||
|
||||
# Attempt to spend a coinbase at depth too low (on a fork this time)
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -257,7 +260,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.sync_blocks([b21], False)
|
||||
|
||||
b22 = self.next_block(22, spend=out[5])
|
||||
self.sync_blocks([b22], False, 16, b'bad-txns-premature-spend-of-coinbase')
|
||||
self.sync_blocks([b22], success=False, reject_code=16, reject_reason=b'bad-txns-premature-spend-of-coinbase')
|
||||
|
||||
# Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
|
||||
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
|
||||
@@ -286,7 +289,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx.vout = [CTxOut(0, script_output)]
|
||||
b24 = self.update_block(24, [tx])
|
||||
assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)
|
||||
self.sync_blocks([b24], False, 16, b'bad-blk-length', reconnect=True)
|
||||
self.sync_blocks([b24], success=False, reject_code=16, reject_reason=b'bad-blk-length', reconnect=True)
|
||||
|
||||
b25 = self.next_block(25, spend=out[7])
|
||||
self.sync_blocks([b25], False)
|
||||
@@ -304,7 +307,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
# update_block causes the merkle root to get updated, even with no new
|
||||
# transactions, and updates the required state.
|
||||
b26 = self.update_block(26, [])
|
||||
self.sync_blocks([b26], False, 16, b'bad-cb-length', reconnect=True)
|
||||
self.sync_blocks([b26], success=False, reject_code=16, reject_reason=b'bad-cb-length', reconnect=True)
|
||||
|
||||
# Extend the b26 chain to make sure bitcoind isn't accepting b26
|
||||
b27 = self.next_block(27, spend=out[7])
|
||||
@@ -316,7 +319,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
|
||||
b28.vtx[0].rehash()
|
||||
b28 = self.update_block(28, [])
|
||||
self.sync_blocks([b28], False, 16, b'bad-cb-length', reconnect=True)
|
||||
self.sync_blocks([b28], success=False, reject_code=16, reject_reason=b'bad-cb-length', reconnect=True)
|
||||
|
||||
# Extend the b28 chain to make sure bitcoind isn't accepting b28
|
||||
b29 = self.next_block(29, spend=out[7])
|
||||
@@ -352,7 +355,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))
|
||||
b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
|
||||
assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)
|
||||
self.sync_blocks([b32], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b32], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
# CHECKMULTISIGVERIFY
|
||||
self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")
|
||||
@@ -365,7 +368,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
|
||||
too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))
|
||||
b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
|
||||
self.sync_blocks([b34], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b34], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
# CHECKSIGVERIFY
|
||||
self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
|
||||
@@ -378,7 +381,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
|
||||
too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))
|
||||
b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
|
||||
self.sync_blocks([b36], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b36], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
# Check spending of a transaction in a block which failed to connect
|
||||
#
|
||||
@@ -395,12 +398,12 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
txout_b37 = b37.vtx[1]
|
||||
tx = self.create_and_sign_transaction(out[11], 0)
|
||||
b37 = self.update_block(37, [tx])
|
||||
self.sync_blocks([b37], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b37], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid
|
||||
self.move_tip(35)
|
||||
b38 = self.next_block(38, spend=txout_b37)
|
||||
self.sync_blocks([b38], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b38], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# Check P2SH SigOp counting
|
||||
#
|
||||
@@ -492,7 +495,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx.rehash()
|
||||
new_txs.append(tx)
|
||||
self.update_block(40, new_txs)
|
||||
self.sync_blocks([b40], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b40], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
# same as b40, but one less sigop
|
||||
self.log.info("Accept a block with the max number of P2SH sigops")
|
||||
@@ -555,7 +558,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1
|
||||
self.tip = b45
|
||||
self.blocks[45] = b45
|
||||
self.sync_blocks([b45], False, 16, b'bad-cb-missing', reconnect=True)
|
||||
self.sync_blocks([b45], success=False, reject_code=16, reject_reason=b'bad-cb-missing', reconnect=True)
|
||||
|
||||
self.log.info("Reject a block with no transactions")
|
||||
self.move_tip(44)
|
||||
@@ -570,7 +573,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
self.tip = b46
|
||||
assert 46 not in self.blocks
|
||||
self.blocks[46] = b46
|
||||
self.sync_blocks([b46], False, 16, b'bad-blk-length', reconnect=True)
|
||||
self.sync_blocks([b46], success=False, reject_code=16, reject_reason=b'bad-blk-length', reconnect=True)
|
||||
|
||||
self.log.info("Reject a block with invalid work")
|
||||
self.move_tip(44)
|
||||
@@ -593,7 +596,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b49 = self.next_block(49)
|
||||
b49.hashMerkleRoot += 1
|
||||
b49.solve()
|
||||
self.sync_blocks([b49], False, 16, b'bad-txnmrklroot', reconnect=True)
|
||||
self.sync_blocks([b49], success=False, reject_code=16, reject_reason=b'bad-txnmrklroot', reconnect=True)
|
||||
|
||||
self.log.info("Reject a block with incorrect POW limit")
|
||||
self.move_tip(44)
|
||||
@@ -607,7 +610,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b51 = self.next_block(51)
|
||||
cb2 = create_coinbase(51, self.coinbase_pubkey)
|
||||
b51 = self.update_block(51, [cb2])
|
||||
self.sync_blocks([b51], False, 16, b'bad-cb-multiple', reconnect=True)
|
||||
self.sync_blocks([b51], success=False, reject_code=16, reject_reason=b'bad-cb-multiple', reconnect=True)
|
||||
|
||||
self.log.info("Reject a block with duplicate transactions")
|
||||
# Note: txns have to be in the right position in the merkle tree to trigger this error
|
||||
@@ -615,7 +618,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b52 = self.next_block(52, spend=out[15])
|
||||
tx = self.create_tx(b52.vtx[1], 0, 1)
|
||||
b52 = self.update_block(52, [tx, tx])
|
||||
self.sync_blocks([b52], False, 16, b'bad-txns-duplicate', reconnect=True)
|
||||
self.sync_blocks([b52], success=False, reject_code=16, reject_reason=b'bad-txns-duplicate', reconnect=True)
|
||||
|
||||
# Test block timestamps
|
||||
# -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
|
||||
@@ -682,7 +685,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
assert_equal(len(b56.vtx), 3)
|
||||
b56 = self.update_block(56, [tx1])
|
||||
assert_equal(b56.hash, b57.hash)
|
||||
self.sync_blocks([b56], False, 16, b'bad-txns-duplicate', reconnect=True)
|
||||
self.sync_blocks([b56], success=False, reject_code=16, reject_reason=b'bad-txns-duplicate', reconnect=True)
|
||||
|
||||
# b57p2 - a good block with 6 tx'es, don't submit until end
|
||||
self.move_tip(55)
|
||||
@@ -702,7 +705,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
assert_equal(b56p2.hash, b57p2.hash)
|
||||
assert_equal(len(b56p2.vtx), 6)
|
||||
b56p2 = self.update_block("b56p2", [tx3, tx4])
|
||||
self.sync_blocks([b56p2], False, 16, b'bad-txns-duplicate', reconnect=True)
|
||||
self.sync_blocks([b56p2], success=False, reject_code=16, reject_reason=b'bad-txns-duplicate', reconnect=True)
|
||||
|
||||
self.move_tip("57p2")
|
||||
self.sync_blocks([b57p2], True)
|
||||
@@ -727,7 +730,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx.vout.append(CTxOut(0, b""))
|
||||
tx.calc_sha256()
|
||||
b58 = self.update_block(58, [tx])
|
||||
self.sync_blocks([b58], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b58], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# tx with output value > input value
|
||||
self.log.info("Reject a block with a transaction with outputs > inputs")
|
||||
@@ -735,7 +738,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b59 = self.next_block(59)
|
||||
tx = self.create_and_sign_transaction(out[17], 51 * COIN)
|
||||
b59 = self.update_block(59, [tx])
|
||||
self.sync_blocks([b59], False, 16, b'bad-txns-in-belowout', reconnect=True)
|
||||
self.sync_blocks([b59], success=False, reject_code=16, reject_reason=b'bad-txns-in-belowout', reconnect=True)
|
||||
|
||||
# reset to good chain
|
||||
self.move_tip(57)
|
||||
@@ -759,7 +762,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b61.vtx[0].rehash()
|
||||
b61 = self.update_block(61, [])
|
||||
assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
|
||||
self.sync_blocks([b61], False, 16, b'bad-txns-BIP30', reconnect=True)
|
||||
self.sync_blocks([b61], success=False, reject_code=16, reject_reason=b'bad-txns-BIP30', reconnect=True)
|
||||
|
||||
# Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
|
||||
#
|
||||
@@ -776,7 +779,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
assert(tx.vin[0].nSequence < 0xffffffff)
|
||||
tx.calc_sha256()
|
||||
b62 = self.update_block(62, [tx])
|
||||
self.sync_blocks([b62], False, 16, b'bad-txns-nonfinal')
|
||||
self.sync_blocks([b62], success=False, reject_code=16, reject_reason=b'bad-txns-nonfinal')
|
||||
|
||||
# Test a non-final coinbase is also rejected
|
||||
#
|
||||
@@ -790,7 +793,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
|
||||
b63.vtx[0].rehash()
|
||||
b63 = self.update_block(63, [])
|
||||
self.sync_blocks([b63], False, 16, b'bad-txns-nonfinal')
|
||||
self.sync_blocks([b63], success=False, reject_code=16, reject_reason=b'bad-txns-nonfinal')
|
||||
|
||||
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that
|
||||
# the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
|
||||
@@ -824,7 +827,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
|
||||
b64a = self.update_block("64a", [tx])
|
||||
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
|
||||
self.sync_blocks([b64a], False, 1, b'error parsing message')
|
||||
self.sync_blocks([b64a], success=False, reject_code=1, reject_reason=b'error parsing message')
|
||||
|
||||
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
|
||||
# resend the header message, it won't send us the getdata message again. Just
|
||||
@@ -866,7 +869,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
|
||||
tx2 = self.create_and_sign_transaction(tx1, 1)
|
||||
b66 = self.update_block(66, [tx2, tx1])
|
||||
self.sync_blocks([b66], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b66], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# Attempt to double-spend a transaction created in a block
|
||||
#
|
||||
@@ -881,7 +884,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx2 = self.create_and_sign_transaction(tx1, 1)
|
||||
tx3 = self.create_and_sign_transaction(tx1, 2)
|
||||
b67 = self.update_block(67, [tx1, tx2, tx3])
|
||||
self.sync_blocks([b67], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b67], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# More tests of block subsidy
|
||||
#
|
||||
@@ -900,7 +903,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b68 = self.next_block(68, additional_coinbase_value=10)
|
||||
tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)
|
||||
b68 = self.update_block(68, [tx])
|
||||
self.sync_blocks([b68], False, 16, b'bad-cb-amount', reconnect=True)
|
||||
self.sync_blocks([b68], success=False, reject_code=16, reject_reason=b'bad-cb-amount', reconnect=True)
|
||||
|
||||
self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")
|
||||
self.move_tip(65)
|
||||
@@ -924,7 +927,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
|
||||
tx.vout.append(CTxOut(1, b""))
|
||||
b70 = self.update_block(70, [tx])
|
||||
self.sync_blocks([b70], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b70], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
# Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
|
||||
#
|
||||
@@ -949,7 +952,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
assert_equal(b72.sha256, b71.sha256)
|
||||
|
||||
self.move_tip(71)
|
||||
self.sync_blocks([b71], False, 16, b'bad-txns-duplicate', reconnect=True)
|
||||
self.sync_blocks([b71], success=False, reject_code=16, reject_reason=b'bad-txns-duplicate', reconnect=True)
|
||||
|
||||
self.move_tip(72)
|
||||
self.sync_blocks([b72], True)
|
||||
@@ -987,7 +990,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
|
||||
b73 = self.update_block(73, [tx])
|
||||
assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)
|
||||
self.sync_blocks([b73], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b73], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
# b74/75 - if we push an invalid script element, all prevous sigops are counted,
|
||||
# but sigops after the element are not counted.
|
||||
@@ -1011,7 +1014,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
a[MAX_BLOCK_SIGOPS + 4] = 0xff
|
||||
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
|
||||
b74 = self.update_block(74, [tx])
|
||||
self.sync_blocks([b74], False, 16, b'bad-blk-sigops', reconnect=True)
|
||||
self.sync_blocks([b74], success=False, reject_code=16, reject_reason=b'bad-blk-sigops', reconnect=True)
|
||||
|
||||
self.move_tip(72)
|
||||
b75 = self.next_block(75)
|
||||
@@ -1160,7 +1163,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
b89a = self.next_block("89a", spend=out[32])
|
||||
tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
|
||||
b89a = self.update_block("89a", [tx])
|
||||
self.sync_blocks([b89a], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
self.sync_blocks([b89a], success=False, reject_code=16, reject_reason=b'bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
||||
self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)")
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ class BlocksdirTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.stop_node(0)
|
||||
shutil.rmtree(self.nodes[0].datadir)
|
||||
|
||||
@@ -57,6 +57,9 @@ class BIP65Test(BitcoinTestFramework):
|
||||
self.extra_args = [['-whitelist=127.0.0.1']]
|
||||
self.setup_clean_chain = True
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
|
||||
@@ -14,8 +14,32 @@ class ConfArgsTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def test_config_file_parser(self):
|
||||
# Assume node is stopped
|
||||
|
||||
inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf')
|
||||
with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf:
|
||||
conf.write('includeconf={}\n'.format(inc_conf_file_path))
|
||||
|
||||
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
|
||||
conf.write('-dash=1\n')
|
||||
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -')
|
||||
|
||||
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
|
||||
conf.write('nono\n')
|
||||
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead')
|
||||
|
||||
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
|
||||
conf.write('') # clear
|
||||
|
||||
def run_test(self):
|
||||
self.stop_node(0)
|
||||
|
||||
self.test_config_file_parser()
|
||||
|
||||
# Remove the -datadir argument so it doesn't override the config file
|
||||
self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")]
|
||||
|
||||
|
||||
@@ -145,6 +145,9 @@ class BIP68_112_113Test(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4', '-addresstype=legacy']]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def generate_blocks(self, number, version, test_blocks=None):
|
||||
if test_blocks is None:
|
||||
test_blocks = []
|
||||
|
||||
@@ -63,6 +63,9 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
|
||||
self.node3_args = ["-blockmaxweight=4000000"]
|
||||
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
self.add_nodes(self.num_nodes, extra_args=self.extra_args)
|
||||
self.start_nodes()
|
||||
|
||||
@@ -45,6 +45,9 @@ class BIP66Test(BitcoinTestFramework):
|
||||
self.extra_args = [['-whitelist=127.0.0.1']]
|
||||
self.setup_clean_chain = True
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
|
||||
@@ -126,6 +126,9 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 3
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
"""
|
||||
We'll setup the network to have 3 nodes that all mine with different parameters.
|
||||
@@ -168,6 +171,11 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
newmem.append(utx)
|
||||
self.memutxo = newmem
|
||||
|
||||
def import_deterministic_coinbase_privkeys(self):
|
||||
self.start_nodes()
|
||||
super().import_deterministic_coinbase_privkeys()
|
||||
self.stop_nodes()
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("This test is time consuming, please be patient")
|
||||
self.log.info("Splitting inputs so we can generate tx's")
|
||||
|
||||
@@ -15,6 +15,9 @@ class LoggingTest(BitcoinTestFramework):
|
||||
self.num_nodes = 1
|
||||
self.setup_clean_chain = True
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def relative_log_path(self, name):
|
||||
return os.path.join(self.nodes[0].datadir, "regtest", name)
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
# Cache for utxos, as the listunspent may take a long time later in the test
|
||||
self.utxo_cache = []
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
# Before we connect anything, we first set the time on the node
|
||||
# to be in the past, otherwise things break because the CNode
|
||||
|
||||
@@ -31,6 +31,9 @@ class MinimumChainWorkTest(BitcoinTestFramework):
|
||||
self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]]
|
||||
self.node_min_work = [0, 101, 101]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
# This test relies on the chain setup being:
|
||||
# node0 <- node1 <- node2
|
||||
|
||||
@@ -13,6 +13,9 @@ class NotificationsTest(BitcoinTestFramework):
|
||||
self.num_nodes = 2
|
||||
self.setup_clean_chain = True
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
|
||||
self.block_filename = os.path.join(self.options.tmpdir, "blocks.txt")
|
||||
|
||||
@@ -44,9 +44,12 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
||||
# normal segwit activation here (and don't use the default always-on behaviour).
|
||||
self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.address = self.nodes[0].getnewaddress()
|
||||
self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])['address']
|
||||
self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address])['address']
|
||||
self.wit_address = self.nodes[0].addwitnessaddress(self.address)
|
||||
self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address']
|
||||
|
||||
|
||||
@@ -33,15 +33,20 @@ class PruneTest(BitcoinTestFramework):
|
||||
|
||||
# Create nodes 0 and 1 to mine.
|
||||
# Create node 2 to test pruning.
|
||||
self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000" ]
|
||||
self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000"]
|
||||
# Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
|
||||
# Create nodes 5 to test wallet in prune mode, but do not connect
|
||||
self.extra_args = [self.full_node_default_args,
|
||||
self.full_node_default_args,
|
||||
["-maxreceivebuffer=20000", "-prune=550"],
|
||||
["-maxreceivebuffer=20000"],
|
||||
["-maxreceivebuffer=20000"],
|
||||
["-prune=550"]]
|
||||
self.extra_args = [
|
||||
self.full_node_default_args,
|
||||
self.full_node_default_args,
|
||||
["-maxreceivebuffer=20000", "-prune=550"],
|
||||
["-maxreceivebuffer=20000"],
|
||||
["-maxreceivebuffer=20000"],
|
||||
["-prune=550"],
|
||||
]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
self.setup_nodes()
|
||||
|
||||
@@ -61,17 +61,26 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
|
||||
|
||||
return COutPoint(int(txid, 16), 0)
|
||||
|
||||
class ReplaceByFeeTest(BitcoinTestFramework):
|
||||
|
||||
class ReplaceByFeeTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
self.extra_args= [["-maxorphantx=1000",
|
||||
"-whitelist=127.0.0.1",
|
||||
"-limitancestorcount=50",
|
||||
"-limitancestorsize=101",
|
||||
"-limitdescendantcount=200",
|
||||
"-limitdescendantsize=101"],
|
||||
["-mempoolreplacement=0"]]
|
||||
self.extra_args = [
|
||||
[
|
||||
"-maxorphantx=1000",
|
||||
"-whitelist=127.0.0.1",
|
||||
"-limitancestorcount=50",
|
||||
"-limitancestorsize=101",
|
||||
"-limitdescendantcount=200",
|
||||
"-limitdescendantsize=101",
|
||||
],
|
||||
[
|
||||
"-mempoolreplacement=0",
|
||||
],
|
||||
]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
# Leave IBD
|
||||
|
||||
@@ -18,6 +18,9 @@ class ReindexTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def reindex(self, justchainstate=False):
|
||||
self.nodes[0].generate(3)
|
||||
blockcount = self.nodes[0].getblockcount()
|
||||
|
||||
@@ -46,9 +46,30 @@ class SegWitTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 3
|
||||
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
|
||||
self.extra_args = [["-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
|
||||
["-blockversion=4", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
|
||||
["-blockversion=536870915", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
|
||||
self.extra_args = [
|
||||
[
|
||||
"-rpcserialversion=0",
|
||||
"-vbparams=segwit:0:999999999999",
|
||||
"-addresstype=legacy",
|
||||
"-deprecatedrpc=addwitnessaddress",
|
||||
],
|
||||
[
|
||||
"-blockversion=4",
|
||||
"-rpcserialversion=1",
|
||||
"-vbparams=segwit:0:999999999999",
|
||||
"-addresstype=legacy",
|
||||
"-deprecatedrpc=addwitnessaddress",
|
||||
],
|
||||
[
|
||||
"-blockversion=536870915",
|
||||
"-vbparams=segwit:0:999999999999",
|
||||
"-addresstype=legacy",
|
||||
"-deprecatedrpc=addwitnessaddress",
|
||||
],
|
||||
]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
super().setup_network()
|
||||
|
||||
@@ -31,6 +31,9 @@ class VersionBitsWarningTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
|
||||
# Open and close to create zero-length file
|
||||
|
||||
@@ -12,6 +12,9 @@ class TestBitcoinCli(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
"""Main test logic"""
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ class RESTTest (BitcoinTestFramework):
|
||||
self.num_nodes = 2
|
||||
self.extra_args = [["-rest"], []]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, body='', status=200, ret_type=RetType.JSON):
|
||||
rest_uri = '/rest' + uri
|
||||
if req_type == ReqType.JSON:
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
"""Test the ZMQ notification interface."""
|
||||
import struct
|
||||
|
||||
from test_framework.test_framework import (
|
||||
BitcoinTestFramework, skip_if_no_bitcoind_zmq, skip_if_no_py3_zmq)
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.messages import CTransaction
|
||||
from test_framework.util import (assert_equal,
|
||||
bytes_to_hex_str,
|
||||
hash256,
|
||||
)
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
bytes_to_hex_str,
|
||||
hash256,
|
||||
)
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class ZMQSubscriber:
|
||||
def __init__(self, socket, topic):
|
||||
self.sequence = 0
|
||||
@@ -37,9 +38,18 @@ class ZMQTest (BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_py3_zmq()
|
||||
self.skip_if_no_bitcoind_zmq()
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_nodes(self):
|
||||
skip_if_no_py3_zmq()
|
||||
skip_if_no_bitcoind_zmq(self)
|
||||
# Import keys
|
||||
self.add_nodes(self.num_nodes)
|
||||
self.start_nodes()
|
||||
super().import_deterministic_coinbase_privkeys()
|
||||
self.stop_nodes()
|
||||
|
||||
import zmq
|
||||
|
||||
# Initialize ZMQ context and socket.
|
||||
@@ -59,10 +69,12 @@ class ZMQTest (BitcoinTestFramework):
|
||||
self.rawblock = ZMQSubscriber(socket, b"rawblock")
|
||||
self.rawtx = ZMQSubscriber(socket, b"rawtx")
|
||||
|
||||
self.extra_args = [["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], []]
|
||||
self.add_nodes(self.num_nodes, self.extra_args)
|
||||
self.nodes[0].extra_args = ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]]
|
||||
self.start_nodes()
|
||||
|
||||
def import_deterministic_coinbase_privkeys(self):
|
||||
pass
|
||||
|
||||
def run_test(self):
|
||||
try:
|
||||
self._zmq_test()
|
||||
|
||||
@@ -40,6 +40,9 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
'-acceptnonstdtxn=0', # Try to mimic main-net
|
||||
]] * self.num_nodes
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def check_mempool_result(self, result_expected, *args, **kwargs):
|
||||
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
|
||||
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
|
||||
|
||||
@@ -15,6 +15,9 @@ class MempoolLimitTest(BitcoinTestFramework):
|
||||
self.num_nodes = 1
|
||||
self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
txouts = gen_return_txouts()
|
||||
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
|
||||
|
||||
@@ -18,6 +18,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||
self.num_nodes = 2
|
||||
self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
# Build a transaction that spends parent_txid:vout
|
||||
# Return amount sent
|
||||
def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs):
|
||||
@@ -34,7 +37,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||
return (txid, send_value)
|
||||
|
||||
def run_test(self):
|
||||
''' Mine some blocks and have them mature. '''
|
||||
# Mine some blocks and have them mature.
|
||||
self.nodes[0].generate(101)
|
||||
utxo = self.nodes[0].listunspent(10)
|
||||
txid = utxo[0]['txid']
|
||||
|
||||
@@ -47,6 +47,9 @@ class MempoolPersistTest(BitcoinTestFramework):
|
||||
self.num_nodes = 3
|
||||
self.extra_args = [[], ["-persistmempool=0"], []]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
chain_height = self.nodes[0].getblockcount()
|
||||
assert_equal(chain_height, 200)
|
||||
|
||||
@@ -17,6 +17,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
alert_filename = None # Set by setup_network
|
||||
|
||||
def run_test(self):
|
||||
|
||||
@@ -13,6 +13,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
node0_address = self.nodes[0].getnewaddress()
|
||||
# Spend block 1/2/3's coinbase transactions
|
||||
@@ -44,12 +47,11 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
||||
tx = self.nodes[0].gettransaction(txid)
|
||||
assert(tx["confirmations"] > 0)
|
||||
|
||||
# Use invalidateblock to re-org back; all transactions should
|
||||
# end up unconfirmed and back in the mempool
|
||||
# Use invalidateblock to re-org back
|
||||
for node in self.nodes:
|
||||
node.invalidateblock(blocks[0])
|
||||
|
||||
# mempool should be empty, all txns confirmed
|
||||
# All txns should be back in mempool with 0 confirmations
|
||||
assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))
|
||||
for txid in spends1_id+spends2_id:
|
||||
tx = self.nodes[0].gettransaction(txid)
|
||||
|
||||
@@ -21,6 +21,9 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
chain_height = self.nodes[0].getblockcount()
|
||||
assert_equal(chain_height, 200)
|
||||
|
||||
@@ -31,6 +31,9 @@ class MiningTest(BitcoinTestFramework):
|
||||
self.num_nodes = 2
|
||||
self.setup_clean_chain = False
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
|
||||
self.nodes[0].generate(10)
|
||||
@@ -70,4 +73,3 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
|
||||
|
||||
if __name__ == '__main__':
|
||||
GetBlockTemplateLPTest().main()
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||
self.num_nodes = 2
|
||||
self.extra_args = [["-printpriority=1"], ["-printpriority=1"]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
# Test `prioritisetransaction` required parameters
|
||||
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction)
|
||||
|
||||
@@ -102,6 +102,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
||||
self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex", "-deprecatedrpc=addwitnessaddress"]]
|
||||
self.utxos = []
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def build_block_on_tip(self, node, segwit=False):
|
||||
height = node.getblockcount()
|
||||
tip = node.getbestblockhash()
|
||||
|
||||
@@ -42,6 +42,9 @@ class FeeFilterTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 2
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
node1 = self.nodes[1]
|
||||
node0 = self.nodes[0]
|
||||
|
||||
@@ -30,6 +30,9 @@ class P2PFingerprintTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
# Build a chain of blocks on top of given one
|
||||
def build_chain(self, nblocks, prev_hash, prev_height, prev_median_time):
|
||||
blocks = []
|
||||
|
||||
@@ -24,6 +24,9 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.extra_args = [["-whitelist=127.0.0.1"]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
# Add p2p connection to node0
|
||||
node = self.nodes[0] # convenience reference to the node
|
||||
@@ -42,7 +45,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
|
||||
# Save the coinbase for later
|
||||
block1 = block
|
||||
tip = block.sha256
|
||||
node.p2p.send_blocks_and_test([block1], node, True)
|
||||
node.p2p.send_blocks_and_test([block1], node, success=True)
|
||||
|
||||
self.log.info("Mature the block.")
|
||||
node.generate(100)
|
||||
@@ -77,9 +80,19 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
|
||||
block2.vtx.append(tx2)
|
||||
assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root())
|
||||
assert_equal(orig_hash, block2.rehash())
|
||||
assert(block2_orig.vtx != block2.vtx)
|
||||
assert block2_orig.vtx != block2.vtx
|
||||
|
||||
node.p2p.send_blocks_and_test([block2], node, False, False, 16, b'bad-txns-duplicate')
|
||||
node.p2p.send_blocks_and_test([block2], node, success=False, reject_code=16, reject_reason=b'bad-txns-duplicate')
|
||||
|
||||
# Check transactions for duplicate inputs
|
||||
self.log.info("Test duplicate input block.")
|
||||
|
||||
block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0])
|
||||
block2_orig.vtx[2].rehash()
|
||||
block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root()
|
||||
block2_orig.rehash()
|
||||
block2_orig.solve()
|
||||
node.p2p.send_blocks_and_test([block2_orig], node, success=False, reject_reason=b'bad-txns-inputs-duplicate')
|
||||
|
||||
self.log.info("Test very broken block.")
|
||||
|
||||
@@ -92,7 +105,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
|
||||
block3.rehash()
|
||||
block3.solve()
|
||||
|
||||
node.p2p.send_blocks_and_test([block3], node, False, False, 16, b'bad-cb-amount')
|
||||
node.p2p.send_blocks_and_test([block3], node, success=False, reject_code=16, reject_reason=b'bad-cb-amount')
|
||||
|
||||
if __name__ == '__main__':
|
||||
InvalidBlockRequestTest().main()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user