merge with bitcoin core
This commit is contained in:
commit
d60d54ddb3
85 changed files with 2917 additions and 1002 deletions
|
@ -38,7 +38,7 @@ fixes or code moves with actual code changes.
|
||||||
Commit messages should be verbose by default consisting of a short subject line
|
Commit messages should be verbose by default consisting of a short subject line
|
||||||
(50 chars max), a blank line and detailed explanatory text as separate
|
(50 chars max), a blank line and detailed explanatory text as separate
|
||||||
paragraph(s); unless the title alone is self-explanatory (like "Corrected typo
|
paragraph(s); unless the title alone is self-explanatory (like "Corrected typo
|
||||||
in main.cpp") then a single title line is sufficient. Commit messages should be
|
in init.cpp") then a single title line is sufficient. Commit messages should be
|
||||||
helpful to people reading your code in the future, so explain the reasoning for
|
helpful to people reading your code in the future, so explain the reasoning for
|
||||||
your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
|
your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ Examples:
|
||||||
Consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG
|
Consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG
|
||||||
Net: Automatically create hidden service, listen on Tor
|
Net: Automatically create hidden service, listen on Tor
|
||||||
Qt: Add feed bump button
|
Qt: Add feed bump button
|
||||||
Trivial: Fix typo in main.cpp
|
Trivial: Fix typo in init.cpp
|
||||||
|
|
||||||
If a pull request is specifically not to be considered for merging (yet) please
|
If a pull request is specifically not to be considered for merging (yet) please
|
||||||
prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists)
|
prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists)
|
||||||
|
@ -194,7 +194,7 @@ request. Typically reviewers will review the code for obvious errors, as well as
|
||||||
test out the patch set and opine on the technical merits of the patch. Project
|
test out the patch set and opine on the technical merits of the patch. Project
|
||||||
maintainers take into account the peer review when determining if there is
|
maintainers take into account the peer review when determining if there is
|
||||||
consensus to merge a pull request (remember that discussions may have been
|
consensus to merge a pull request (remember that discussions may have been
|
||||||
spread out over github, mailing list and IRC discussions). The following
|
spread out over GitHub, mailing list and IRC discussions). The following
|
||||||
language is used within pull-request comments:
|
language is used within pull-request comments:
|
||||||
|
|
||||||
- ACK means "I have tested the code and I agree it should be merged";
|
- ACK means "I have tested the code and I agree it should be merged";
|
||||||
|
|
|
@ -227,9 +227,6 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-
|
||||||
|
|
||||||
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
|
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
|
||||||
|
|
||||||
# This file is problematic for out-of-tree builds if it exists.
|
|
||||||
DISTCLEANFILES = qa/pull-tester/tests_config.pyc
|
|
||||||
|
|
||||||
.INTERMEDIATE: $(COVERAGE_INFO)
|
.INTERMEDIATE: $(COVERAGE_INFO)
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --enable-man
|
DISTCHECK_CONFIGURE_FLAGS = --enable-man
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||||
AC_PREREQ([2.60])
|
AC_PREREQ([2.60])
|
||||||
define(_CLIENT_VERSION_MAJOR, 0)
|
define(_CLIENT_VERSION_MAJOR, 0)
|
||||||
define(_CLIENT_VERSION_MINOR, 13)
|
define(_CLIENT_VERSION_MINOR, 14)
|
||||||
define(_CLIENT_VERSION_REVISION, 99)
|
define(_CLIENT_VERSION_REVISION, 99)
|
||||||
define(_CLIENT_VERSION_BUILD, 0)
|
define(_CLIENT_VERSION_BUILD, 0)
|
||||||
define(_CLIENT_VERSION_IS_RELEASE, false)
|
define(_CLIENT_VERSION_IS_RELEASE, false)
|
||||||
|
@ -1087,7 +1087,7 @@ AC_SUBST(ZMQ_LIBS)
|
||||||
AC_SUBST(PROTOBUF_LIBS)
|
AC_SUBST(PROTOBUF_LIBS)
|
||||||
AC_SUBST(QR_LIBS)
|
AC_SUBST(QR_LIBS)
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
|
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
|
||||||
AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py])
|
AC_CONFIG_FILES([qa/pull-tester/tests_config.ini],[chmod +x qa/pull-tester/tests_config.ini])
|
||||||
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
|
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
|
||||||
AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py])
|
AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py])
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ Repository Tools
|
||||||
|
|
||||||
### [Developer tools](/contrib/devtools) ###
|
### [Developer tools](/contrib/devtools) ###
|
||||||
Specific tools for developers working on this repository.
|
Specific tools for developers working on this repository.
|
||||||
Contains the script `github-merge.py` for merging github pull requests securely and signing them using GPG.
|
Contains the script `github-merge.py` for merging GitHub pull requests securely and signing them using GPG.
|
||||||
|
|
||||||
### [Verify-Commits](/contrib/verify-commits) ###
|
### [Verify-Commits](/contrib/verify-commits) ###
|
||||||
Tool to verify that every merge commit was signed by a developer using the above `github-merge.py` script.
|
Tool to verify that every merge commit was signed by a developer using the above `github-merge.py` script.
|
||||||
|
|
|
@ -125,7 +125,7 @@ check or whatever).
|
||||||
|
|
||||||
This means that there are no potential race conditions (where a
|
This means that there are no potential race conditions (where a
|
||||||
pullreq gets updated while you're reviewing it, but before you click
|
pullreq gets updated while you're reviewing it, but before you click
|
||||||
merge), and when using GPG signatures, that even a compromised github
|
merge), and when using GPG signatures, that even a compromised GitHub
|
||||||
couldn't mess with the sources.
|
couldn't mess with the sources.
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
|
|
|
@ -65,6 +65,14 @@ def split_format_specifiers(specifiers):
|
||||||
else:
|
else:
|
||||||
other.append(s)
|
other.append(s)
|
||||||
|
|
||||||
|
# If both numeric format specifiers and "others" are used, assume we're dealing
|
||||||
|
# with a Qt-formatted message. In the case of Qt formatting (see https://doc.qt.io/qt-5/qstring.html#arg)
|
||||||
|
# only numeric formats are replaced at all. This means "(percentage: %1%)" is valid, without needing
|
||||||
|
# any kind of escaping that would be necessary for strprintf. Without this, this function
|
||||||
|
# would wrongly detect '%)' as a printf format specifier.
|
||||||
|
if numeric:
|
||||||
|
other = []
|
||||||
|
|
||||||
# numeric (Qt) can be present in any order, others (strprintf) must be in specified order
|
# numeric (Qt) can be present in any order, others (strprintf) must be in specified order
|
||||||
return set(numeric),other
|
return set(numeric),other
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
name: "bitcoin-linux-0.13"
|
name: "bitcoin-linux-0.15"
|
||||||
enable_cache: true
|
enable_cache: true
|
||||||
suites:
|
suites:
|
||||||
- "trusty"
|
- "trusty"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
name: "bitcoin-osx-0.13"
|
name: "bitcoin-osx-0.15"
|
||||||
enable_cache: true
|
enable_cache: true
|
||||||
suites:
|
suites:
|
||||||
- "trusty"
|
- "trusty"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
name: "bitcoin-win-0.13"
|
name: "bitcoin-win-0.15"
|
||||||
enable_cache: true
|
enable_cache: true
|
||||||
suites:
|
suites:
|
||||||
- "trusty"
|
- "trusty"
|
||||||
|
|
|
@ -1,43 +1,84 @@
|
||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
"""
|
||||||
|
ZMQ example using python3's asyncio
|
||||||
|
|
||||||
|
Bitcoin should be started with the command line arguments:
|
||||||
|
bitcoind -testnet -daemon \
|
||||||
|
-zmqpubhashblock=tcp://127.0.0.1:28332 \
|
||||||
|
-zmqpubrawtx=tcp://127.0.0.1:28332 \
|
||||||
|
-zmqpubhashtx=tcp://127.0.0.1:28332 \
|
||||||
|
-zmqpubhashblock=tcp://127.0.0.1:28332
|
||||||
|
|
||||||
|
We use the asyncio library here. `self.handle()` installs itself as a
|
||||||
|
future at the end of the function. Since it never returns with the event
|
||||||
|
loop having an empty stack of futures, this creates an infinite loop. An
|
||||||
|
alternative is to wrap the contents of `handle` inside `while True`.
|
||||||
|
|
||||||
|
A blocking example using python 2.7 can be obtained from the git history:
|
||||||
|
https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
|
||||||
|
"""
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
|
import asyncio
|
||||||
import zmq
|
import zmq
|
||||||
|
import zmq.asyncio
|
||||||
|
import signal
|
||||||
import struct
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if not (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
|
||||||
|
print("This example only works with Python 3.5 and greater")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
port = 28332
|
port = 28332
|
||||||
|
|
||||||
zmqContext = zmq.Context()
|
class ZMQHandler():
|
||||||
zmqSubSocket = zmqContext.socket(zmq.SUB)
|
def __init__(self):
|
||||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashblock")
|
self.loop = zmq.asyncio.install()
|
||||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashtx")
|
self.zmqContext = zmq.asyncio.Context()
|
||||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawblock")
|
|
||||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawtx")
|
|
||||||
zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
|
|
||||||
|
|
||||||
try:
|
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
|
||||||
while True:
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
|
||||||
msg = zmqSubSocket.recv_multipart()
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
|
||||||
topic = str(msg[0])
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
|
||||||
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
|
||||||
|
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
|
||||||
|
|
||||||
|
async def handle(self) :
|
||||||
|
msg = await self.zmqSubSocket.recv_multipart()
|
||||||
|
topic = msg[0]
|
||||||
body = msg[1]
|
body = msg[1]
|
||||||
sequence = "Unknown"
|
sequence = "Unknown"
|
||||||
if len(msg[-1]) == 4:
|
if len(msg[-1]) == 4:
|
||||||
msgSequence = struct.unpack('<I', msg[-1])[-1]
|
msgSequence = struct.unpack('<I', msg[-1])[-1]
|
||||||
sequence = str(msgSequence)
|
sequence = str(msgSequence)
|
||||||
if topic == "hashblock":
|
if topic == b"hashblock":
|
||||||
print '- HASH BLOCK ('+sequence+') -'
|
print('- HASH BLOCK ('+sequence+') -')
|
||||||
print binascii.hexlify(body)
|
print(binascii.hexlify(body))
|
||||||
elif topic == "hashtx":
|
elif topic == b"hashtx":
|
||||||
print '- HASH TX ('+sequence+') -'
|
print('- HASH TX ('+sequence+') -')
|
||||||
print binascii.hexlify(body)
|
print(binascii.hexlify(body))
|
||||||
elif topic == "rawblock":
|
elif topic == b"rawblock":
|
||||||
print '- RAW BLOCK HEADER ('+sequence+') -'
|
print('- RAW BLOCK HEADER ('+sequence+') -')
|
||||||
print binascii.hexlify(body[:80])
|
print(binascii.hexlify(body[:80]))
|
||||||
elif topic == "rawtx":
|
elif topic == b"rawtx":
|
||||||
print '- RAW TX ('+sequence+') -'
|
print('- RAW TX ('+sequence+') -')
|
||||||
print binascii.hexlify(body)
|
print(binascii.hexlify(body))
|
||||||
|
# schedule ourselves to receive the next message
|
||||||
|
asyncio.ensure_future(self.handle())
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
def start(self):
|
||||||
zmqContext.destroy()
|
self.loop.add_signal_handler(signal.SIGINT, self.stop)
|
||||||
|
self.loop.create_task(self.handle())
|
||||||
|
self.loop.run_forever()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.loop.stop()
|
||||||
|
self.zmqContext.destroy()
|
||||||
|
|
||||||
|
daemon = ZMQHandler()
|
||||||
|
daemon.start()
|
||||||
|
|
89
contrib/zmq/zmq_sub3.4.py
Executable file
89
contrib/zmq/zmq_sub3.4.py
Executable file
|
@ -0,0 +1,89 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
"""
|
||||||
|
ZMQ example using python3's asyncio
|
||||||
|
|
||||||
|
Bitcoin should be started with the command line arguments:
|
||||||
|
bitcoind -testnet -daemon \
|
||||||
|
-zmqpubhashblock=tcp://127.0.0.1:28332 \
|
||||||
|
-zmqpubrawtx=tcp://127.0.0.1:28332 \
|
||||||
|
-zmqpubhashtx=tcp://127.0.0.1:28332 \
|
||||||
|
-zmqpubhashblock=tcp://127.0.0.1:28332
|
||||||
|
|
||||||
|
We use the asyncio library here. `self.handle()` installs itself as a
|
||||||
|
future at the end of the function. Since it never returns with the event
|
||||||
|
loop having an empty stack of futures, this creates an infinite loop. An
|
||||||
|
alternative is to wrap the contents of `handle` inside `while True`.
|
||||||
|
|
||||||
|
The `@asyncio.coroutine` decorator and the `yield from` syntax found here
|
||||||
|
was introduced in python 3.4 and has been deprecated in favor of the `async`
|
||||||
|
and `await` keywords respectively.
|
||||||
|
|
||||||
|
A blocking example using python 2.7 can be obtained from the git history:
|
||||||
|
https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import asyncio
|
||||||
|
import zmq
|
||||||
|
import zmq.asyncio
|
||||||
|
import signal
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if not (sys.version_info.major >= 3 and sys.version_info.minor >= 4):
|
||||||
|
print("This example only works with Python 3.4 and greater")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
port = 28332
|
||||||
|
|
||||||
|
class ZMQHandler():
|
||||||
|
def __init__(self):
|
||||||
|
self.loop = zmq.asyncio.install()
|
||||||
|
self.zmqContext = zmq.asyncio.Context()
|
||||||
|
|
||||||
|
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
|
||||||
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
|
||||||
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
|
||||||
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
|
||||||
|
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
|
||||||
|
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def handle(self) :
|
||||||
|
msg = yield from self.zmqSubSocket.recv_multipart()
|
||||||
|
topic = msg[0]
|
||||||
|
body = msg[1]
|
||||||
|
sequence = "Unknown";
|
||||||
|
if len(msg[-1]) == 4:
|
||||||
|
msgSequence = struct.unpack('<I', msg[-1])[-1]
|
||||||
|
sequence = str(msgSequence)
|
||||||
|
if topic == b"hashblock":
|
||||||
|
print('- HASH BLOCK ('+sequence+') -')
|
||||||
|
print(binascii.hexlify(body))
|
||||||
|
elif topic == b"hashtx":
|
||||||
|
print('- HASH TX ('+sequence+') -')
|
||||||
|
print(binascii.hexlify(body))
|
||||||
|
elif topic == b"rawblock":
|
||||||
|
print('- RAW BLOCK HEADER ('+sequence+') -')
|
||||||
|
print(binascii.hexlify(body[:80]))
|
||||||
|
elif topic == b"rawtx":
|
||||||
|
print('- RAW TX ('+sequence+') -')
|
||||||
|
print(binascii.hexlify(body))
|
||||||
|
# schedule ourselves to receive the next message
|
||||||
|
asyncio.ensure_future(self.handle())
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.loop.add_signal_handler(signal.SIGINT, self.stop)
|
||||||
|
self.loop.create_task(self.handle())
|
||||||
|
self.loop.run_forever()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.loop.stop()
|
||||||
|
self.zmqContext.destroy()
|
||||||
|
|
||||||
|
daemon = ZMQHandler()
|
||||||
|
daemon.start()
|
|
@ -1,7 +1,7 @@
|
||||||
package=qrencode
|
package=qrencode
|
||||||
$(package)_version=3.4.4
|
$(package)_version=3.4.4
|
||||||
$(package)_download_path=https://fukuchi.org/works/qrencode/
|
$(package)_download_path=https://fukuchi.org/works/qrencode/
|
||||||
$(package)_file_name=qrencode-$(qrencode_version).tar.bz2
|
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
|
||||||
$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5
|
$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5
|
||||||
|
|
||||||
define $(package)_set_vars
|
define $(package)_set_vars
|
||||||
|
|
|
@ -38,7 +38,7 @@ PROJECT_NAME = "Bitcoin Core"
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 0.13.99
|
PROJECT_NUMBER = 0.14.99
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Bitcoin Core 0.13.99
|
Bitcoin Core 0.14.99
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Bitcoin Core 0.13.99
|
Bitcoin Core 0.14.99
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Intro
|
Intro
|
||||||
|
|
|
@ -448,7 +448,7 @@ Current subtrees include:
|
||||||
- Upstream at https://github.com/jgarzik/univalue ; report important PRs to Core to avoid delay.
|
- Upstream at https://github.com/jgarzik/univalue ; report important PRs to Core to avoid delay.
|
||||||
|
|
||||||
|
|
||||||
Git and github tips
|
Git and GitHub tips
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
- For resolving merge/rebase conflicts, it can be useful to enable diff3 style using
|
- For resolving merge/rebase conflicts, it can be useful to enable diff3 style using
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||||
.TH BITCOIN-CLI "1" "September 2016" "bitcoin-cli v0.13.0.0" "User Commands"
|
.TH BITCOIN-CLI "1" "February 2017" "bitcoin-cli v0.14.99.0" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
bitcoin-cli \- manual page for bitcoin-cli v0.13.0.0
|
bitcoin-cli \- manual page for bitcoin-cli v0.14.99.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Bitcoin Core RPC client version v0.13.0.0
|
Bitcoin Core RPC client version v0.14.99.0
|
||||||
.SS "Usage:"
|
.SS "Usage:"
|
||||||
.TP
|
.TP
|
||||||
bitcoin\-cli [options] <command> [params]
|
bitcoin\-cli [options] <command> [params]
|
||||||
Send command to Bitcoin Core
|
Send command to Bitcoin Core
|
||||||
.TP
|
.IP
|
||||||
bitcoin\-cli [options] help
|
bitcoin\-cli [options] \fB\-named\fR <command> [name=value] ... Send command to Bitcoin Core (with named arguments)
|
||||||
List commands
|
bitcoin\-cli [options] help List commands
|
||||||
.TP
|
bitcoin\-cli [options] help <command> Get help for a command
|
||||||
bitcoin\-cli [options] help <command>
|
|
||||||
Get help for a command
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.HP
|
.HP
|
||||||
\-?
|
\-?
|
||||||
|
@ -40,6 +38,10 @@ Enter regression test mode, which uses a special chain in which blocks
|
||||||
can be solved instantly. This is intended for regression testing
|
can be solved instantly. This is intended for regression testing
|
||||||
tools and app development.
|
tools and app development.
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-named\fR
|
||||||
|
.IP
|
||||||
|
Pass named instead of positional arguments (default: false)
|
||||||
|
.HP
|
||||||
\fB\-rpcconnect=\fR<ip>
|
\fB\-rpcconnect=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
Send commands to node running on <ip> (default: 127.0.0.1)
|
Send commands to node running on <ip> (default: 127.0.0.1)
|
||||||
|
@ -69,7 +71,7 @@ Timeout during HTTP requests (default: 900)
|
||||||
Read extra arguments from standard input, one per line until EOF/Ctrl\-D
|
Read extra arguments from standard input, one per line until EOF/Ctrl\-D
|
||||||
(recommended for sensitive information such as passphrases)
|
(recommended for sensitive information such as passphrases)
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright (C) 2009-2016 The Bitcoin Core developers
|
Copyright (C) 2009-2017 The Bitcoin Core developers
|
||||||
|
|
||||||
Please contribute if you find Bitcoin Core useful. Visit
|
Please contribute if you find Bitcoin Core useful. Visit
|
||||||
<https://bitcoincore.org> for further information about the software.
|
<https://bitcoincore.org> for further information about the software.
|
||||||
|
@ -77,8 +79,8 @@ The source code is available from <https://github.com/bitcoin/bitcoin>.
|
||||||
|
|
||||||
This is experimental software.
|
This is experimental software.
|
||||||
Distributed under the MIT software license, see the accompanying file COPYING
|
Distributed under the MIT software license, see the accompanying file COPYING
|
||||||
or <http://www.opensource.org/licenses/mit-license.php>.
|
or <https://opensource.org/licenses/MIT>
|
||||||
|
|
||||||
This product includes software developed by the OpenSSL Project for use in the
|
This product includes software developed by the OpenSSL Project for use in the
|
||||||
OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
|
OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
|
||||||
by Eric Young and UPnP software written by Thomas Bernard.
|
Eric Young and UPnP software written by Thomas Bernard.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||||
.TH BITCOIN-QT "1" "September 2016" "bitcoin-qt v0.13.0.0" "User Commands"
|
.TH BITCOIN-QT "1" "February 2017" "bitcoin-qt v0.14.99.0" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
bitcoin-qt \- manual page for bitcoin-qt v0.13.0.0
|
bitcoin-qt \- manual page for bitcoin-qt v0.14.99.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Bitcoin Core version v0.13.0.0 (64\-bit)
|
Bitcoin Core version v0.14.99.0 (64\-bit)
|
||||||
Usage:
|
Usage:
|
||||||
.IP
|
.IP
|
||||||
bitcoin\-qt [command\-line options]
|
bitcoin\-qt [command\-line options]
|
||||||
|
@ -27,13 +27,14 @@ long fork (%s in cmd is replaced by message)
|
||||||
Execute command when the best block changes (%s in cmd is replaced by
|
Execute command when the best block changes (%s in cmd is replaced by
|
||||||
block hash)
|
block hash)
|
||||||
.HP
|
.HP
|
||||||
\fB\-checkblocks=\fR<n>
|
\fB\-assumevalid=\fR<hex>
|
||||||
.IP
|
.IP
|
||||||
How many blocks to check at startup (default: 288, 0 = all)
|
If this block is in the chain assume that it and its ancestors are valid
|
||||||
.HP
|
and potentially skip their script verification (0 to verify all,
|
||||||
\fB\-checklevel=\fR<n>
|
default:
|
||||||
.IP
|
00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90,
|
||||||
How thorough the block verification of \fB\-checkblocks\fR is (0\-4, default: 3)
|
testnet:
|
||||||
|
00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc)
|
||||||
.HP
|
.HP
|
||||||
\fB\-conf=\fR<file>
|
\fB\-conf=\fR<file>
|
||||||
.IP
|
.IP
|
||||||
|
@ -62,11 +63,16 @@ Keep the transaction memory pool below <n> megabytes (default: 300)
|
||||||
\fB\-mempoolexpiry=\fR<n>
|
\fB\-mempoolexpiry=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
Do not keep transactions in the mempool longer than <n> hours (default:
|
Do not keep transactions in the mempool longer than <n> hours (default:
|
||||||
72)
|
336)
|
||||||
|
.HP
|
||||||
|
\fB\-blockreconstructionextratxn=\fR<n>
|
||||||
|
.IP
|
||||||
|
Extra transactions to keep in memory for compact block reconstructions
|
||||||
|
(default: 100)
|
||||||
.HP
|
.HP
|
||||||
\fB\-par=\fR<n>
|
\fB\-par=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 =
|
Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 =
|
||||||
leave that many cores free, default: 0)
|
leave that many cores free, default: 0)
|
||||||
.HP
|
.HP
|
||||||
\fB\-pid=\fR<file>
|
\fB\-pid=\fR<file>
|
||||||
|
@ -75,13 +81,15 @@ Specify pid file (default: bitcoind.pid)
|
||||||
.HP
|
.HP
|
||||||
\fB\-prune=\fR<n>
|
\fB\-prune=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
Reduce storage requirements by enabling pruning (deleting) of old blocks.
|
Reduce storage requirements by enabling pruning (deleting) of old
|
||||||
This allows the pruneblockchain RPC to be called to delete specific blocks,
|
blocks. This allows the pruneblockchain RPC to be called to
|
||||||
and enables automatic pruning of old blocks if a target size in MiB is
|
delete specific blocks, and enables automatic pruning of old
|
||||||
provided. This mode is incompatible with \fB\-txindex\fR and \fB\-rescan\fR.
|
blocks if a target size in MiB is provided. This mode is
|
||||||
Warning: Reverting this setting requires re\-downloading the entire blockchain.
|
incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
|
||||||
(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >550 =
|
setting requires re\-downloading the entire blockchain. (default:
|
||||||
automatically prune block files to stay under the specified target size in MiB)
|
0 = disable pruning blocks, 1 = allow manual pruning via RPC,
|
||||||
|
>550 = automatically prune block files to stay under the
|
||||||
|
specified target size in MiB)
|
||||||
.HP
|
.HP
|
||||||
\fB\-reindex\-chainstate\fR
|
\fB\-reindex\-chainstate\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -123,7 +131,8 @@ for IPv6
|
||||||
.HP
|
.HP
|
||||||
\fB\-connect=\fR<ip>
|
\fB\-connect=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
Connect only to the specified node(s)
|
Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to
|
||||||
|
disable automatic connections
|
||||||
.HP
|
.HP
|
||||||
\fB\-discover\fR
|
\fB\-discover\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -137,7 +146,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def
|
||||||
\fB\-dnsseed\fR
|
\fB\-dnsseed\fR
|
||||||
.IP
|
.IP
|
||||||
Query for peer addresses via DNS lookup, if low on addresses (default: 1
|
Query for peer addresses via DNS lookup, if low on addresses (default: 1
|
||||||
unless \fB\-connect\fR)
|
unless \fB\-connect\fR/\-noconnect)
|
||||||
.HP
|
.HP
|
||||||
\fB\-externalip=\fR<ip>
|
\fB\-externalip=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
|
@ -149,7 +158,8 @@ Always query for peer addresses via DNS lookup (default: 0)
|
||||||
.HP
|
.HP
|
||||||
\fB\-listen\fR
|
\fB\-listen\fR
|
||||||
.IP
|
.IP
|
||||||
Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR)
|
Accept connections from outside (default: 1 if no \fB\-proxy\fR or
|
||||||
|
\fB\-connect\fR/\-noconnect)
|
||||||
.HP
|
.HP
|
||||||
\fB\-listenonion\fR
|
\fB\-listenonion\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -204,6 +214,11 @@ Connect through SOCKS5 proxy
|
||||||
Randomize credentials for every proxy connection. This enables Tor
|
Randomize credentials for every proxy connection. This enables Tor
|
||||||
stream isolation (default: 1)
|
stream isolation (default: 1)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-rpcserialversion\fR
|
||||||
|
.IP
|
||||||
|
Sets the serialization of raw transaction or block hex returned in
|
||||||
|
non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1)
|
||||||
|
.HP
|
||||||
\fB\-seednode=\fR<ip>
|
\fB\-seednode=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
Connect to a node to retrieve peer addresses, and disconnect
|
Connect to a node to retrieve peer addresses, and disconnect
|
||||||
|
@ -221,17 +236,22 @@ Tor control port to use if onion listening enabled (default:
|
||||||
.IP
|
.IP
|
||||||
Tor control port password (default: empty)
|
Tor control port password (default: empty)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-upnp\fR
|
||||||
|
.IP
|
||||||
|
Use UPnP to map the listening port (default: 0)
|
||||||
|
.HP
|
||||||
\fB\-whitebind=\fR<addr>
|
\fB\-whitebind=\fR<addr>
|
||||||
.IP
|
.IP
|
||||||
Bind to given address and whitelist peers connecting to it. Use
|
Bind to given address and whitelist peers connecting to it. Use
|
||||||
[host]:port notation for IPv6
|
[host]:port notation for IPv6
|
||||||
.HP
|
.HP
|
||||||
\fB\-whitelist=\fR<netmask>
|
\fB\-whitelist=\fR<IP address or network>
|
||||||
.IP
|
.IP
|
||||||
Whitelist peers connecting from the given netmask or IP address. Can be
|
Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or
|
||||||
specified multiple times. Whitelisted peers cannot be DoS banned
|
CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple
|
||||||
and their transactions are always relayed, even if they are
|
times. Whitelisted peers cannot be DoS banned and their
|
||||||
already in the mempool, useful e.g. for a gateway
|
transactions are always relayed, even if they are already in the
|
||||||
|
mempool, useful e.g. for a gateway
|
||||||
.HP
|
.HP
|
||||||
\fB\-whitelistrelay\fR
|
\fB\-whitelistrelay\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -240,7 +260,7 @@ not relaying transactions (default: 1)
|
||||||
.HP
|
.HP
|
||||||
\fB\-whitelistforcerelay\fR
|
\fB\-whitelistforcerelay\fR
|
||||||
.IP
|
.IP
|
||||||
Force relay of transactions from whitelisted peers even they violate
|
Force relay of transactions from whitelisted peers even if they violate
|
||||||
local relay policy (default: 1)
|
local relay policy (default: 1)
|
||||||
.HP
|
.HP
|
||||||
\fB\-maxuploadtarget=\fR<n>
|
\fB\-maxuploadtarget=\fR<n>
|
||||||
|
@ -287,13 +307,17 @@ Spend unconfirmed change when sending transactions (default: 1)
|
||||||
\fB\-txconfirmtarget=\fR<n>
|
\fB\-txconfirmtarget=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
If paytxfee is not set, include enough fee so transactions begin
|
If paytxfee is not set, include enough fee so transactions begin
|
||||||
confirmation on average within n blocks (default: 2)
|
confirmation on average within n blocks (default: 6)
|
||||||
.HP
|
.HP
|
||||||
\fB\-usehd\fR
|
\fB\-usehd\fR
|
||||||
.IP
|
.IP
|
||||||
Use hierarchical deterministic key generation (HD) after BIP32. Only has
|
Use hierarchical deterministic key generation (HD) after BIP32. Only has
|
||||||
effect during wallet creation/first start (default: 1)
|
effect during wallet creation/first start (default: 1)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-walletrbf\fR
|
||||||
|
.IP
|
||||||
|
Send transactions with full\-RBF opt\-in enabled (default: 0)
|
||||||
|
.HP
|
||||||
\fB\-upgradewallet\fR
|
\fB\-upgradewallet\fR
|
||||||
.IP
|
.IP
|
||||||
Upgrade wallet to latest format on startup
|
Upgrade wallet to latest format on startup
|
||||||
|
@ -347,9 +371,9 @@ Append comment to the user agent string
|
||||||
Output debugging information (default: 0, supplying <category> is
|
Output debugging information (default: 0, supplying <category> is
|
||||||
optional). If <category> is not supplied or if <category> = 1,
|
optional). If <category> is not supplied or if <category> = 1,
|
||||||
output all debugging information.<category> can be: addrman,
|
output all debugging information.<category> can be: addrman,
|
||||||
alert, bench, coindb, db, http, libevent, lock, mempool,
|
alert, bench, cmpctblock, coindb, db, http, libevent, lock,
|
||||||
mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins,
|
mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc,
|
||||||
tor, zmq, qt.
|
selectcoins, tor, zmq, qt.
|
||||||
.HP
|
.HP
|
||||||
\fB\-help\-debug\fR
|
\fB\-help\-debug\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -422,6 +446,11 @@ Set maximum block size in bytes (default: 750000)
|
||||||
.IP
|
.IP
|
||||||
Set maximum size of high\-priority/low\-fee transactions in bytes
|
Set maximum size of high\-priority/low\-fee transactions in bytes
|
||||||
(default: 0)
|
(default: 0)
|
||||||
|
.HP
|
||||||
|
\fB\-blockmintxfee=\fR<amt>
|
||||||
|
.IP
|
||||||
|
Set lowest fee rate (in BTC/kB) for transactions to be included in block
|
||||||
|
creation. (default: 0.00001)
|
||||||
.PP
|
.PP
|
||||||
RPC server options:
|
RPC server options:
|
||||||
.HP
|
.HP
|
||||||
|
@ -455,8 +484,10 @@ Password for JSON\-RPC connections
|
||||||
.IP
|
.IP
|
||||||
Username and hashed password for JSON\-RPC connections. The field
|
Username and hashed password for JSON\-RPC connections. The field
|
||||||
<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
|
<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
|
||||||
canonical python script is included in share/rpcuser. This option
|
canonical python script is included in share/rpcuser. The client
|
||||||
can be specified multiple times
|
then connects normally using the
|
||||||
|
rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This
|
||||||
|
option can be specified multiple times
|
||||||
.HP
|
.HP
|
||||||
\fB\-rpcport=\fR<port>
|
\fB\-rpcport=\fR<port>
|
||||||
.IP
|
.IP
|
||||||
|
@ -500,7 +531,7 @@ Show splash screen on startup (default: 1)
|
||||||
.IP
|
.IP
|
||||||
Reset all settings changed in the GUI
|
Reset all settings changed in the GUI
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright (C) 2009-2016 The Bitcoin Core developers
|
Copyright (C) 2009-2017 The Bitcoin Core developers
|
||||||
|
|
||||||
Please contribute if you find Bitcoin Core useful. Visit
|
Please contribute if you find Bitcoin Core useful. Visit
|
||||||
<https://bitcoincore.org> for further information about the software.
|
<https://bitcoincore.org> for further information about the software.
|
||||||
|
@ -508,8 +539,8 @@ The source code is available from <https://github.com/bitcoin/bitcoin>.
|
||||||
|
|
||||||
This is experimental software.
|
This is experimental software.
|
||||||
Distributed under the MIT software license, see the accompanying file COPYING
|
Distributed under the MIT software license, see the accompanying file COPYING
|
||||||
or <http://www.opensource.org/licenses/mit-license.php>.
|
or <https://opensource.org/licenses/MIT>
|
||||||
|
|
||||||
This product includes software developed by the OpenSSL Project for use in the
|
This product includes software developed by the OpenSSL Project for use in the
|
||||||
OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
|
OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
|
||||||
by Eric Young and UPnP software written by Thomas Bernard.
|
Eric Young and UPnP software written by Thomas Bernard.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||||
.TH BITCOIN-TX "1" "September 2016" "bitcoin-tx v0.13.0.0" "User Commands"
|
.TH BITCOIN-TX "1" "February 2017" "bitcoin-tx v0.14.99.0" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
bitcoin-tx \- manual page for bitcoin-tx v0.13.0.0
|
bitcoin-tx \- manual page for bitcoin-tx v0.14.99.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Bitcoin Core bitcoin\-tx utility version v0.13.0.0
|
Bitcoin Core bitcoin\-tx utility version v0.14.99.0
|
||||||
.SS "Usage:"
|
.SS "Usage:"
|
||||||
.TP
|
.TP
|
||||||
bitcoin\-tx [options] <hex\-tx> [commands]
|
bitcoin\-tx [options] <hex\-tx> [commands]
|
||||||
|
@ -67,13 +67,28 @@ outaddr=VALUE:ADDRESS
|
||||||
.IP
|
.IP
|
||||||
Add address\-based output to TX
|
Add address\-based output to TX
|
||||||
.IP
|
.IP
|
||||||
|
outpubkey=VALUE:PUBKEY[:FLAGS]
|
||||||
|
.IP
|
||||||
|
Add pay\-to\-pubkey output to TX. Optionally add the "W" flag to produce a
|
||||||
|
pay\-to\-witness\-pubkey\-hash output. Optionally add the "S" flag to
|
||||||
|
wrap the output in a pay\-to\-script\-hash.
|
||||||
|
.IP
|
||||||
outdata=[VALUE:]DATA
|
outdata=[VALUE:]DATA
|
||||||
.IP
|
.IP
|
||||||
Add data\-based output to TX
|
Add data\-based output to TX
|
||||||
.IP
|
.IP
|
||||||
outscript=VALUE:SCRIPT
|
outscript=VALUE:SCRIPT[:FLAGS]
|
||||||
.IP
|
.IP
|
||||||
Add raw script output to TX
|
Add raw script output to TX. Optionally add the "W" flag to produce a
|
||||||
|
pay\-to\-witness\-script\-hash output. Optionally add the "S" flag to
|
||||||
|
wrap the output in a pay\-to\-script\-hash.
|
||||||
|
.IP
|
||||||
|
outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
|
||||||
|
.IP
|
||||||
|
Add Pay To n\-of\-m Multi\-sig output to TX. n = REQUIRED, m = PUBKEYS.
|
||||||
|
Optionally add the "W" flag to produce a
|
||||||
|
pay\-to\-witness\-script\-hash output. Optionally add the "S" flag to
|
||||||
|
wrap the output in a pay\-to\-script\-hash.
|
||||||
.IP
|
.IP
|
||||||
sign=SIGHASH\-FLAGS
|
sign=SIGHASH\-FLAGS
|
||||||
.IP
|
.IP
|
||||||
|
@ -92,7 +107,7 @@ set=NAME:JSON\-STRING
|
||||||
.IP
|
.IP
|
||||||
Set register NAME to given JSON\-STRING
|
Set register NAME to given JSON\-STRING
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright (C) 2009-2016 The Bitcoin Core developers
|
Copyright (C) 2009-2017 The Bitcoin Core developers
|
||||||
|
|
||||||
Please contribute if you find Bitcoin Core useful. Visit
|
Please contribute if you find Bitcoin Core useful. Visit
|
||||||
<https://bitcoincore.org> for further information about the software.
|
<https://bitcoincore.org> for further information about the software.
|
||||||
|
@ -100,8 +115,8 @@ The source code is available from <https://github.com/bitcoin/bitcoin>.
|
||||||
|
|
||||||
This is experimental software.
|
This is experimental software.
|
||||||
Distributed under the MIT software license, see the accompanying file COPYING
|
Distributed under the MIT software license, see the accompanying file COPYING
|
||||||
or <http://www.opensource.org/licenses/mit-license.php>.
|
or <https://opensource.org/licenses/MIT>
|
||||||
|
|
||||||
This product includes software developed by the OpenSSL Project for use in the
|
This product includes software developed by the OpenSSL Project for use in the
|
||||||
OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
|
OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
|
||||||
by Eric Young and UPnP software written by Thomas Bernard.
|
Eric Young and UPnP software written by Thomas Bernard.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||||
.TH BITCOIND "1" "September 2016" "bitcoind v0.13.0.0" "User Commands"
|
.TH BITCOIND "1" "February 2017" "bitcoind v0.14.99.0" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
bitcoind \- manual page for bitcoind v0.13.0.0
|
bitcoind \- manual page for bitcoind v0.14.99.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Bitcoin Core Daemon version v0.13.0.0
|
Bitcoin Core Daemon version v0.14.99.0
|
||||||
.SS "Usage:"
|
.SS "Usage:"
|
||||||
.TP
|
.TP
|
||||||
bitcoind [options]
|
bitcoind [options]
|
||||||
|
@ -28,13 +28,14 @@ long fork (%s in cmd is replaced by message)
|
||||||
Execute command when the best block changes (%s in cmd is replaced by
|
Execute command when the best block changes (%s in cmd is replaced by
|
||||||
block hash)
|
block hash)
|
||||||
.HP
|
.HP
|
||||||
\fB\-checkblocks=\fR<n>
|
\fB\-assumevalid=\fR<hex>
|
||||||
.IP
|
.IP
|
||||||
How many blocks to check at startup (default: 288, 0 = all)
|
If this block is in the chain assume that it and its ancestors are valid
|
||||||
.HP
|
and potentially skip their script verification (0 to verify all,
|
||||||
\fB\-checklevel=\fR<n>
|
default:
|
||||||
.IP
|
00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90,
|
||||||
How thorough the block verification of \fB\-checkblocks\fR is (0\-4, default: 3)
|
testnet:
|
||||||
|
00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc)
|
||||||
.HP
|
.HP
|
||||||
\fB\-conf=\fR<file>
|
\fB\-conf=\fR<file>
|
||||||
.IP
|
.IP
|
||||||
|
@ -67,11 +68,16 @@ Keep the transaction memory pool below <n> megabytes (default: 300)
|
||||||
\fB\-mempoolexpiry=\fR<n>
|
\fB\-mempoolexpiry=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
Do not keep transactions in the mempool longer than <n> hours (default:
|
Do not keep transactions in the mempool longer than <n> hours (default:
|
||||||
72)
|
336)
|
||||||
|
.HP
|
||||||
|
\fB\-blockreconstructionextratxn=\fR<n>
|
||||||
|
.IP
|
||||||
|
Extra transactions to keep in memory for compact block reconstructions
|
||||||
|
(default: 100)
|
||||||
.HP
|
.HP
|
||||||
\fB\-par=\fR<n>
|
\fB\-par=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 =
|
Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 =
|
||||||
leave that many cores free, default: 0)
|
leave that many cores free, default: 0)
|
||||||
.HP
|
.HP
|
||||||
\fB\-pid=\fR<file>
|
\fB\-pid=\fR<file>
|
||||||
|
@ -80,13 +86,15 @@ Specify pid file (default: bitcoind.pid)
|
||||||
.HP
|
.HP
|
||||||
\fB\-prune=\fR<n>
|
\fB\-prune=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
Reduce storage requirements by enabling pruning (deleting) of old blocks.
|
Reduce storage requirements by enabling pruning (deleting) of old
|
||||||
This allows the pruneblockchain RPC to be called to delete specific blocks,
|
blocks. This allows the pruneblockchain RPC to be called to
|
||||||
and enables automatic pruning of old blocks if a target size in MiB is
|
delete specific blocks, and enables automatic pruning of old
|
||||||
provided. This mode is incompatible with \fB\-txindex\fR and \fB\-rescan\fR.
|
blocks if a target size in MiB is provided. This mode is
|
||||||
Warning: Reverting this setting requires re\-downloading the entire blockchain.
|
incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
|
||||||
(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >550 =
|
setting requires re\-downloading the entire blockchain. (default:
|
||||||
automatically prune block files to stay under the specified target size in MiB)
|
0 = disable pruning blocks, 1 = allow manual pruning via RPC,
|
||||||
|
>550 = automatically prune block files to stay under the
|
||||||
|
specified target size in MiB)
|
||||||
.HP
|
.HP
|
||||||
\fB\-reindex\-chainstate\fR
|
\fB\-reindex\-chainstate\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -128,7 +136,8 @@ for IPv6
|
||||||
.HP
|
.HP
|
||||||
\fB\-connect=\fR<ip>
|
\fB\-connect=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
Connect only to the specified node(s)
|
Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to
|
||||||
|
disable automatic connections
|
||||||
.HP
|
.HP
|
||||||
\fB\-discover\fR
|
\fB\-discover\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -142,7 +151,7 @@ Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (def
|
||||||
\fB\-dnsseed\fR
|
\fB\-dnsseed\fR
|
||||||
.IP
|
.IP
|
||||||
Query for peer addresses via DNS lookup, if low on addresses (default: 1
|
Query for peer addresses via DNS lookup, if low on addresses (default: 1
|
||||||
unless \fB\-connect\fR)
|
unless \fB\-connect\fR/\-noconnect)
|
||||||
.HP
|
.HP
|
||||||
\fB\-externalip=\fR<ip>
|
\fB\-externalip=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
|
@ -154,7 +163,8 @@ Always query for peer addresses via DNS lookup (default: 0)
|
||||||
.HP
|
.HP
|
||||||
\fB\-listen\fR
|
\fB\-listen\fR
|
||||||
.IP
|
.IP
|
||||||
Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR)
|
Accept connections from outside (default: 1 if no \fB\-proxy\fR or
|
||||||
|
\fB\-connect\fR/\-noconnect)
|
||||||
.HP
|
.HP
|
||||||
\fB\-listenonion\fR
|
\fB\-listenonion\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -209,6 +219,11 @@ Connect through SOCKS5 proxy
|
||||||
Randomize credentials for every proxy connection. This enables Tor
|
Randomize credentials for every proxy connection. This enables Tor
|
||||||
stream isolation (default: 1)
|
stream isolation (default: 1)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-rpcserialversion\fR
|
||||||
|
.IP
|
||||||
|
Sets the serialization of raw transaction or block hex returned in
|
||||||
|
non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1)
|
||||||
|
.HP
|
||||||
\fB\-seednode=\fR<ip>
|
\fB\-seednode=\fR<ip>
|
||||||
.IP
|
.IP
|
||||||
Connect to a node to retrieve peer addresses, and disconnect
|
Connect to a node to retrieve peer addresses, and disconnect
|
||||||
|
@ -226,17 +241,22 @@ Tor control port to use if onion listening enabled (default:
|
||||||
.IP
|
.IP
|
||||||
Tor control port password (default: empty)
|
Tor control port password (default: empty)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-upnp\fR
|
||||||
|
.IP
|
||||||
|
Use UPnP to map the listening port (default: 0)
|
||||||
|
.HP
|
||||||
\fB\-whitebind=\fR<addr>
|
\fB\-whitebind=\fR<addr>
|
||||||
.IP
|
.IP
|
||||||
Bind to given address and whitelist peers connecting to it. Use
|
Bind to given address and whitelist peers connecting to it. Use
|
||||||
[host]:port notation for IPv6
|
[host]:port notation for IPv6
|
||||||
.HP
|
.HP
|
||||||
\fB\-whitelist=\fR<netmask>
|
\fB\-whitelist=\fR<IP address or network>
|
||||||
.IP
|
.IP
|
||||||
Whitelist peers connecting from the given netmask or IP address. Can be
|
Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or
|
||||||
specified multiple times. Whitelisted peers cannot be DoS banned
|
CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple
|
||||||
and their transactions are always relayed, even if they are
|
times. Whitelisted peers cannot be DoS banned and their
|
||||||
already in the mempool, useful e.g. for a gateway
|
transactions are always relayed, even if they are already in the
|
||||||
|
mempool, useful e.g. for a gateway
|
||||||
.HP
|
.HP
|
||||||
\fB\-whitelistrelay\fR
|
\fB\-whitelistrelay\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -245,7 +265,7 @@ not relaying transactions (default: 1)
|
||||||
.HP
|
.HP
|
||||||
\fB\-whitelistforcerelay\fR
|
\fB\-whitelistforcerelay\fR
|
||||||
.IP
|
.IP
|
||||||
Force relay of transactions from whitelisted peers even they violate
|
Force relay of transactions from whitelisted peers even if they violate
|
||||||
local relay policy (default: 1)
|
local relay policy (default: 1)
|
||||||
.HP
|
.HP
|
||||||
\fB\-maxuploadtarget=\fR<n>
|
\fB\-maxuploadtarget=\fR<n>
|
||||||
|
@ -292,13 +312,17 @@ Spend unconfirmed change when sending transactions (default: 1)
|
||||||
\fB\-txconfirmtarget=\fR<n>
|
\fB\-txconfirmtarget=\fR<n>
|
||||||
.IP
|
.IP
|
||||||
If paytxfee is not set, include enough fee so transactions begin
|
If paytxfee is not set, include enough fee so transactions begin
|
||||||
confirmation on average within n blocks (default: 2)
|
confirmation on average within n blocks (default: 6)
|
||||||
.HP
|
.HP
|
||||||
\fB\-usehd\fR
|
\fB\-usehd\fR
|
||||||
.IP
|
.IP
|
||||||
Use hierarchical deterministic key generation (HD) after BIP32. Only has
|
Use hierarchical deterministic key generation (HD) after BIP32. Only has
|
||||||
effect during wallet creation/first start (default: 1)
|
effect during wallet creation/first start (default: 1)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-walletrbf\fR
|
||||||
|
.IP
|
||||||
|
Send transactions with full\-RBF opt\-in enabled (default: 0)
|
||||||
|
.HP
|
||||||
\fB\-upgradewallet\fR
|
\fB\-upgradewallet\fR
|
||||||
.IP
|
.IP
|
||||||
Upgrade wallet to latest format on startup
|
Upgrade wallet to latest format on startup
|
||||||
|
@ -352,9 +376,9 @@ Append comment to the user agent string
|
||||||
Output debugging information (default: 0, supplying <category> is
|
Output debugging information (default: 0, supplying <category> is
|
||||||
optional). If <category> is not supplied or if <category> = 1,
|
optional). If <category> is not supplied or if <category> = 1,
|
||||||
output all debugging information.<category> can be: addrman,
|
output all debugging information.<category> can be: addrman,
|
||||||
alert, bench, coindb, db, http, libevent, lock, mempool,
|
alert, bench, cmpctblock, coindb, db, http, libevent, lock,
|
||||||
mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins,
|
mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc,
|
||||||
tor, zmq.
|
selectcoins, tor, zmq.
|
||||||
.HP
|
.HP
|
||||||
\fB\-help\-debug\fR
|
\fB\-help\-debug\fR
|
||||||
.IP
|
.IP
|
||||||
|
@ -427,6 +451,11 @@ Set maximum block size in bytes (default: 750000)
|
||||||
.IP
|
.IP
|
||||||
Set maximum size of high\-priority/low\-fee transactions in bytes
|
Set maximum size of high\-priority/low\-fee transactions in bytes
|
||||||
(default: 0)
|
(default: 0)
|
||||||
|
.HP
|
||||||
|
\fB\-blockmintxfee=\fR<amt>
|
||||||
|
.IP
|
||||||
|
Set lowest fee rate (in BTC/kB) for transactions to be included in block
|
||||||
|
creation. (default: 0.00001)
|
||||||
.PP
|
.PP
|
||||||
RPC server options:
|
RPC server options:
|
||||||
.HP
|
.HP
|
||||||
|
@ -460,8 +489,10 @@ Password for JSON\-RPC connections
|
||||||
.IP
|
.IP
|
||||||
Username and hashed password for JSON\-RPC connections. The field
|
Username and hashed password for JSON\-RPC connections. The field
|
||||||
<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
|
<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
|
||||||
canonical python script is included in share/rpcuser. This option
|
canonical python script is included in share/rpcuser. The client
|
||||||
can be specified multiple times
|
then connects normally using the
|
||||||
|
rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This
|
||||||
|
option can be specified multiple times
|
||||||
.HP
|
.HP
|
||||||
\fB\-rpcport=\fR<port>
|
\fB\-rpcport=\fR<port>
|
||||||
.IP
|
.IP
|
||||||
|
@ -479,7 +510,7 @@ option can be specified multiple times
|
||||||
.IP
|
.IP
|
||||||
Set the number of threads to service RPC calls (default: 4)
|
Set the number of threads to service RPC calls (default: 4)
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright (C) 2009-2016 The Bitcoin Core developers
|
Copyright (C) 2009-2017 The Bitcoin Core developers
|
||||||
|
|
||||||
Please contribute if you find Bitcoin Core useful. Visit
|
Please contribute if you find Bitcoin Core useful. Visit
|
||||||
<https://bitcoincore.org> for further information about the software.
|
<https://bitcoincore.org> for further information about the software.
|
||||||
|
@ -487,8 +518,8 @@ The source code is available from <https://github.com/bitcoin/bitcoin>.
|
||||||
|
|
||||||
This is experimental software.
|
This is experimental software.
|
||||||
Distributed under the MIT software license, see the accompanying file COPYING
|
Distributed under the MIT software license, see the accompanying file COPYING
|
||||||
or <http://www.opensource.org/licenses/mit-license.php>.
|
or <https://opensource.org/licenses/MIT>
|
||||||
|
|
||||||
This product includes software developed by the OpenSSL Project for use in the
|
This product includes software developed by the OpenSSL Project for use in the
|
||||||
OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
|
OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
|
||||||
by Eric Young and UPnP software written by Thomas Bernard.
|
Eric Young and UPnP software written by Thomas Bernard.
|
||||||
|
|
|
@ -33,117 +33,6 @@ frequently tested on them.
|
||||||
Notable changes
|
Notable changes
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Low-level RPC changes
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
- `importprunedfunds` only accepts two required arguments. Some versions accept
|
|
||||||
an optional third arg, which was always ignored. Make sure to never pass more
|
|
||||||
than two arguments.
|
|
||||||
|
|
||||||
Fee Estimation Changes
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
- Since 0.13.2 fee estimation for a confirmation target of 1 block has been
|
|
||||||
disabled. This is only a minor behavior change as there was often insufficient
|
|
||||||
data for this target anyway. `estimatefee 1` will now always return -1 and
|
|
||||||
`estimatesmartfee 1` will start searching at a target of 2.
|
|
||||||
|
|
||||||
- The default target for fee estimation is changed to 6 blocks in both the GUI
|
|
||||||
(previously 25) and for RPC calls (previously 2).
|
|
||||||
|
|
||||||
Removal of Priority Estimation
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
- Estimation of "priority" needed for a transaction to be included within a target
|
|
||||||
number of blocks has been removed. The rpc calls are deprecated and will either
|
|
||||||
return -1 or 1e24 appropriately. The format for `fee_estimates.dat` has also
|
|
||||||
changed to no longer save these priority estimates. It will automatically be
|
|
||||||
converted to the new format which is not readable by prior versions of the
|
|
||||||
software.
|
|
||||||
|
|
||||||
- The concept of "priority" (coin age) transactions is planned to be removed in
|
|
||||||
the next major version. To prepare for this, the default for the rate limit of
|
|
||||||
priority transactions (`-limitfreerelay`) has been set to `0` kB/minute. This
|
|
||||||
is not to be confused with the `prioritisetransaction` RPC which will remain
|
|
||||||
supported for adding fee deltas to transactions.
|
|
||||||
|
|
||||||
P2P connection management
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
- Peers manually added through the addnode option or addnode RPC now have their own
|
|
||||||
limit of eight connections which does not compete with other inbound or outbound
|
|
||||||
connection usage and is not subject to the maxconnections limitation.
|
|
||||||
|
|
||||||
- New connections to manually added peers are much faster.
|
|
||||||
|
|
||||||
Introduction of assumed-valid blocks
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
- A significant portion of the initial block download time is spent verifying
|
|
||||||
scripts/signatures. Although the verification must pass to ensure the security
|
|
||||||
of the system, no other result from this verification is needed: If the node
|
|
||||||
knew the history of a given block were valid it could skip checking scripts
|
|
||||||
for its ancestors.
|
|
||||||
|
|
||||||
- A new configuration option 'assumevalid' is provided to express this knowledge
|
|
||||||
to the software. Unlike the 'checkpoints' in the past this setting does not
|
|
||||||
force the use of a particular chain: chains that are consistent with it are
|
|
||||||
processed quicker, but other chains are still accepted if they'd otherwise
|
|
||||||
be chosen as best. Also unlike 'checkpoints' the user can configure which
|
|
||||||
block history is assumed true, this means that even outdated software can
|
|
||||||
sync more quickly if the setting is updated by the user.
|
|
||||||
|
|
||||||
- Because the validity of a chain history is a simple objective fact it is much
|
|
||||||
easier to review this setting. As a result the software ships with a default
|
|
||||||
value adjusted to match the current chain shortly before release. The use
|
|
||||||
of this default value can be disabled by setting -assumevalid=0
|
|
||||||
|
|
||||||
0.14.0 Change log
|
|
||||||
=================
|
|
||||||
|
|
||||||
Detailed release notes follow. This overview includes changes that affect
|
|
||||||
behavior, not code moves, refactors and string updates. For convenience in locating
|
|
||||||
the code changes and accompanying discussion, both the pull request and
|
|
||||||
git merge commit are mentioned.
|
|
||||||
|
|
||||||
### RPC and REST
|
|
||||||
|
|
||||||
UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`) responses
|
|
||||||
were changed to return status code HTTP_BAD_REQUEST (400) instead of HTTP_INTERNAL_SERVER_ERROR (500) when requests
|
|
||||||
contain invalid parameters.
|
|
||||||
|
|
||||||
The first boolean argument to `getaddednodeinfo` has been removed. This is an incompatible change.
|
|
||||||
|
|
||||||
Call "getmininginfo" loses the "testnet" field in favor of the more generic "chain" (which has been present for years).
|
|
||||||
|
|
||||||
### Configuration and command-line options
|
|
||||||
|
|
||||||
### Block and transaction handling
|
|
||||||
|
|
||||||
### P2P protocol and network code
|
|
||||||
|
|
||||||
### Validation
|
|
||||||
|
|
||||||
### Build system
|
|
||||||
|
|
||||||
### Wallet
|
|
||||||
|
|
||||||
0.14.0 Fundrawtransaction change address reuse
|
|
||||||
==============================================
|
|
||||||
|
|
||||||
Before 0.14, `fundrawtransaction` was by default wallet stateless. In almost all cases `fundrawtransaction` does add a change-output to the outputs of the funded transaction. Before 0.14, the used keypool key was never marked as change-address key and directly returned to the keypool (leading to address reuse).
|
|
||||||
Before 0.14, calling `getnewaddress` directly after `fundrawtransaction` did generate the same address as the change-output address.
|
|
||||||
|
|
||||||
Since 0.14, fundrawtransaction does reserve the change-output-key from the keypool by default (optional by setting `reserveChangeKey`, default = `true`)
|
|
||||||
|
|
||||||
Users should also consider using `getrawchangeaddress()` in conjunction with `fundrawtransaction`'s `changeAddress` option.
|
|
||||||
|
|
||||||
### GUI
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
### Miscellaneous
|
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ Translations
|
||||||
The Bitcoin-Core project has been designed to support multiple localisations. This makes adding new phrases, and completely new languages easily achievable. For managing all application translations, Bitcoin-Core makes use of the Transifex online translation management tool.
|
The Bitcoin-Core project has been designed to support multiple localisations. This makes adding new phrases, and completely new languages easily achievable. For managing all application translations, Bitcoin-Core makes use of the Transifex online translation management tool.
|
||||||
|
|
||||||
### Helping to translate (using Transifex)
|
### Helping to translate (using Transifex)
|
||||||
Transifex is setup to monitor the Github repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface.
|
Transifex is setup to monitor the GitHub repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface.
|
||||||
|
|
||||||
Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-border money transfers, any help making that easier is greatly appreciated.
|
Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-border money transfers, any help making that easier is greatly appreciated.
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
|
||||||
### Creating a pull-request
|
### Creating a pull-request
|
||||||
For general PRs, you shouldn’t include any updates to the translation source files. They will be updated periodically, primarily around pre-releases, allowing time for any new phrases to be translated before public releases. This is also important in avoiding translation related merge conflicts.
|
For general PRs, you shouldn’t include any updates to the translation source files. They will be updated periodically, primarily around pre-releases, allowing time for any new phrases to be translated before public releases. This is also important in avoiding translation related merge conflicts.
|
||||||
|
|
||||||
When an updated source file is merged into the Github repo, Transifex will automatically detect it (although it can take several hours). Once processed, the new strings will show up as "Remaining" in the Transifex web interface and are ready for translators.
|
When an updated source file is merged into the GitHub repo, Transifex will automatically detect it (although it can take several hours). Once processed, the new strings will show up as "Remaining" in the Transifex web interface and are ready for translators.
|
||||||
|
|
||||||
To create the pull-request, use the following commands:
|
To create the pull-request, use the following commands:
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Block and Transaction Broadcasting With ZeroMQ
|
# Block and Transaction Broadcasting with ZeroMQ
|
||||||
|
|
||||||
[ZeroMQ](http://zeromq.org/) is a lightweight wrapper around TCP
|
[ZeroMQ](http://zeromq.org/) is a lightweight wrapper around TCP
|
||||||
connections, inter-process communication, and shared-memory,
|
connections, inter-process communication, and shared-memory,
|
||||||
|
@ -50,7 +50,7 @@ during the *configure* step of building bitcoind:
|
||||||
$ ./configure --disable-zmq (other options)
|
$ ./configure --disable-zmq (other options)
|
||||||
|
|
||||||
To actually enable operation, one must set the appropriate options on
|
To actually enable operation, one must set the appropriate options on
|
||||||
the commandline or in the configuration file.
|
the command line or in the configuration file.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,21 @@
|
||||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Run Regression Test Suite
|
rpc-tests.py - run regression test suite
|
||||||
|
|
||||||
This module calls down into individual test cases via subprocess. It will
|
This module calls down into individual test cases via subprocess. It will
|
||||||
forward all unrecognized arguments onto the individual test scripts, other
|
forward all unrecognized arguments onto the individual test scripts.
|
||||||
than:
|
|
||||||
|
|
||||||
- `-extended`: run the "extended" test suite in addition to the basic one.
|
RPC tests are disabled on Windows by default. Use --force to run them anyway.
|
||||||
- `-win`: signal that this is running in a Windows environment, and we
|
|
||||||
should run the tests.
|
|
||||||
- `--coverage`: this generates a basic coverage report for the RPC
|
|
||||||
interface.
|
|
||||||
|
|
||||||
For a description of arguments recognized by test scripts, see
|
For a description of arguments recognized by test scripts, see
|
||||||
`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
|
`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -29,77 +25,9 @@ import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import re
|
import re
|
||||||
|
|
||||||
sys.path.append("qa/pull-tester/")
|
BASE_SCRIPTS= [
|
||||||
from tests_config import *
|
# Scripts that are run by the travis build process.
|
||||||
|
# Longest test should go first, to favor running tests in parallel
|
||||||
BOLD = ("","")
|
|
||||||
if os.name == 'posix':
|
|
||||||
# primitive formatting on supported
|
|
||||||
# terminal via ANSI escape sequences:
|
|
||||||
BOLD = ('\033[0m', '\033[1m')
|
|
||||||
|
|
||||||
RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/'
|
|
||||||
|
|
||||||
#If imported values are not defined then set to zero (or disabled)
|
|
||||||
if 'ENABLE_WALLET' not in vars():
|
|
||||||
ENABLE_WALLET=0
|
|
||||||
if 'ENABLE_BITCOIND' not in vars():
|
|
||||||
ENABLE_BITCOIND=0
|
|
||||||
if 'ENABLE_UTILS' not in vars():
|
|
||||||
ENABLE_UTILS=0
|
|
||||||
if 'ENABLE_ZMQ' not in vars():
|
|
||||||
ENABLE_ZMQ=0
|
|
||||||
|
|
||||||
ENABLE_COVERAGE=0
|
|
||||||
|
|
||||||
#Create a set to store arguments and create the passon string
|
|
||||||
opts = set()
|
|
||||||
passon_args = []
|
|
||||||
PASSON_REGEX = re.compile("^--")
|
|
||||||
PARALLEL_REGEX = re.compile('^-parallel=')
|
|
||||||
|
|
||||||
print_help = False
|
|
||||||
run_parallel = 4
|
|
||||||
|
|
||||||
for arg in sys.argv[1:]:
|
|
||||||
if arg == "--help" or arg == "-h" or arg == "-?":
|
|
||||||
print_help = True
|
|
||||||
break
|
|
||||||
if arg == '--coverage':
|
|
||||||
ENABLE_COVERAGE = 1
|
|
||||||
elif PASSON_REGEX.match(arg):
|
|
||||||
passon_args.append(arg)
|
|
||||||
elif PARALLEL_REGEX.match(arg):
|
|
||||||
run_parallel = int(arg.split(sep='=', maxsplit=1)[1])
|
|
||||||
else:
|
|
||||||
opts.add(arg)
|
|
||||||
|
|
||||||
#Set env vars
|
|
||||||
if "BITCOIND" not in os.environ:
|
|
||||||
os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT
|
|
||||||
|
|
||||||
if EXEEXT == ".exe" and "-win" not in opts:
|
|
||||||
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
|
|
||||||
# https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
|
|
||||||
print("Win tests currently disabled by default. Use -win option to enable")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
|
|
||||||
print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# python3-zmq may not be installed. Handle this gracefully and with some helpful info
|
|
||||||
if ENABLE_ZMQ:
|
|
||||||
try:
|
|
||||||
import zmq
|
|
||||||
except ImportError:
|
|
||||||
print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or "
|
|
||||||
"to run zmq tests, see dependency info in /qa/README.md.")
|
|
||||||
# ENABLE_ZMQ=0
|
|
||||||
raise
|
|
||||||
|
|
||||||
testScripts = [
|
|
||||||
# longest test should go first, to favor running tests in parallel
|
|
||||||
'wallet-hd.py',
|
'wallet-hd.py',
|
||||||
'walletbackup.py',
|
'walletbackup.py',
|
||||||
# vv Tests less than 5m vv
|
# vv Tests less than 5m vv
|
||||||
|
@ -154,11 +82,17 @@ testScripts = [
|
||||||
'bumpfee.py',
|
'bumpfee.py',
|
||||||
'rpcnamedargs.py',
|
'rpcnamedargs.py',
|
||||||
'listsinceblock.py',
|
'listsinceblock.py',
|
||||||
|
'p2p-leaktests.py',
|
||||||
]
|
]
|
||||||
if ENABLE_ZMQ:
|
|
||||||
testScripts.append('zmq_test.py')
|
|
||||||
|
|
||||||
testScriptsExt = [
|
ZMQ_SCRIPTS = [
|
||||||
|
# ZMQ test can only be run if bitcoin was built with zmq-enabled.
|
||||||
|
# call rpc_tests.py with -nozmq to explicitly exclude these tests.
|
||||||
|
"zmq_test.py"]
|
||||||
|
|
||||||
|
EXTENDED_SCRIPTS = [
|
||||||
|
# These tests are not run by the travis build process.
|
||||||
|
# Longest test should go first, to favor running tests in parallel
|
||||||
'pruning.py',
|
'pruning.py',
|
||||||
# vv Tests less than 20m vv
|
# vv Tests less than 20m vv
|
||||||
'smartfees.py',
|
'smartfees.py',
|
||||||
|
@ -168,6 +102,7 @@ testScriptsExt = [
|
||||||
# vv Tests less than 2m vv
|
# vv Tests less than 2m vv
|
||||||
'bip68-sequence.py',
|
'bip68-sequence.py',
|
||||||
'getblocktemplate_longpoll.py',
|
'getblocktemplate_longpoll.py',
|
||||||
|
'p2p-timeouts.py',
|
||||||
# vv Tests less than 60s vv
|
# vv Tests less than 60s vv
|
||||||
'bip9-softforks.py',
|
'bip9-softforks.py',
|
||||||
'p2p-feefilter.py',
|
'p2p-feefilter.py',
|
||||||
|
@ -187,44 +122,126 @@ testScriptsExt = [
|
||||||
'replace-by-fee.py',
|
'replace-by-fee.py',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS
|
||||||
|
|
||||||
def runtests():
|
def main():
|
||||||
test_list = []
|
# Parse arguments and pass through unrecognised args
|
||||||
if '-extended' in opts:
|
parser = argparse.ArgumentParser(add_help=False,
|
||||||
test_list = testScripts + testScriptsExt
|
usage='%(prog)s [rpc-test.py options] [script options] [scripts]',
|
||||||
elif len(opts) == 0 or (len(opts) == 1 and "-win" in opts):
|
description=__doc__,
|
||||||
test_list = testScripts
|
epilog='''
|
||||||
else:
|
Help text and arguments for individual test script:''',
|
||||||
for t in testScripts + testScriptsExt:
|
formatter_class=argparse.RawTextHelpFormatter)
|
||||||
if t in opts or re.sub(".py$", "", t) in opts:
|
parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
|
||||||
test_list.append(t)
|
parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')
|
||||||
|
parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
|
||||||
|
parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
|
||||||
|
parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
|
||||||
|
parser.add_argument('--nozmq', action='store_true', help='do not run the zmq tests')
|
||||||
|
args, unknown_args = parser.parse_known_args()
|
||||||
|
|
||||||
if print_help:
|
# Create a set to store arguments and create the passon string
|
||||||
# Only print help of the first script and exit
|
tests = set(arg for arg in unknown_args if arg[:2] != "--")
|
||||||
subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h'])
|
passon_args = [arg for arg in unknown_args if arg[:2] == "--"]
|
||||||
|
|
||||||
|
# Read config generated by configure.
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read_file(open(os.path.dirname(__file__) + "/tests_config.ini"))
|
||||||
|
|
||||||
|
enable_wallet = config["components"].getboolean("ENABLE_WALLET")
|
||||||
|
enable_utils = config["components"].getboolean("ENABLE_UTILS")
|
||||||
|
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
|
||||||
|
enable_zmq = config["components"].getboolean("ENABLE_ZMQ") and not args.nozmq
|
||||||
|
|
||||||
|
if config["environment"]["EXEEXT"] == ".exe" and not args.force:
|
||||||
|
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
|
||||||
|
# https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
|
||||||
|
print("Tests currently disabled on Windows by default. Use --force option to enable")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
if not (enable_wallet and enable_utils and enable_bitcoind):
|
||||||
|
print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
|
||||||
|
print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# python3-zmq may not be installed. Handle this gracefully and with some helpful info
|
||||||
|
if enable_zmq:
|
||||||
|
try:
|
||||||
|
import zmq
|
||||||
|
except ImportError:
|
||||||
|
print("ERROR: \"import zmq\" failed. Use -nozmq to run without the ZMQ tests."
|
||||||
|
"To run zmq tests, see dependency info in /qa/README.md.")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Build list of tests
|
||||||
|
if tests:
|
||||||
|
# Individual tests have been specified. Run specified tests that exist
|
||||||
|
# in the ALL_SCRIPTS list. Accept the name with or without .py extension.
|
||||||
|
test_list = [t for t in ALL_SCRIPTS if
|
||||||
|
(t in tests or re.sub(".py$", "", t) in tests)]
|
||||||
|
if not test_list:
|
||||||
|
print("No valid test scripts specified. Check that your test is in one "
|
||||||
|
"of the test lists in rpc-tests.py or run rpc-tests.py with no arguments to run all tests")
|
||||||
|
print("Scripts not found:")
|
||||||
|
print(tests)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# No individual tests have been specified. Run base tests, and
|
||||||
|
# optionally ZMQ tests and extended tests.
|
||||||
|
test_list = BASE_SCRIPTS
|
||||||
|
if enable_zmq:
|
||||||
|
test_list += ZMQ_SCRIPTS
|
||||||
|
if args.extended:
|
||||||
|
test_list += EXTENDED_SCRIPTS
|
||||||
|
# TODO: BASE_SCRIPTS and EXTENDED_SCRIPTS are sorted by runtime
|
||||||
|
# (for parallel running efficiency). This combined list will is no
|
||||||
|
# longer sorted.
|
||||||
|
|
||||||
|
if args.help:
|
||||||
|
# Print help for rpc-tests.py, then print help of the first script and exit.
|
||||||
|
parser.print_help()
|
||||||
|
subprocess.check_call((config["environment"]["SRCDIR"] + '/qa/rpc-tests/' + test_list[0]).split() + ['-h'])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
|
||||||
|
|
||||||
|
def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
|
||||||
|
BOLD = ("","")
|
||||||
|
if os.name == 'posix':
|
||||||
|
# primitive formatting on supported
|
||||||
|
# terminal via ANSI escape sequences:
|
||||||
|
BOLD = ('\033[0m', '\033[1m')
|
||||||
|
|
||||||
|
#Set env vars
|
||||||
|
if "BITCOIND" not in os.environ:
|
||||||
|
os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext
|
||||||
|
|
||||||
|
tests_dir = src_dir + '/qa/rpc-tests/'
|
||||||
|
|
||||||
|
flags = ["--srcdir=" + src_dir] + args
|
||||||
|
flags.append("--cachedir=%s/qa/cache" % build_dir)
|
||||||
|
|
||||||
|
if enable_coverage:
|
||||||
|
coverage = RPCCoverage()
|
||||||
|
flags.append(coverage.flag)
|
||||||
|
print("Initializing coverage directory at %s\n" % coverage.dir)
|
||||||
|
else:
|
||||||
coverage = None
|
coverage = None
|
||||||
|
|
||||||
if ENABLE_COVERAGE:
|
if len(test_list) > 1 and jobs > 1:
|
||||||
coverage = RPCCoverage()
|
|
||||||
print("Initializing coverage directory at %s\n" % coverage.dir)
|
|
||||||
flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
|
|
||||||
flags.append("--cachedir=%s/qa/cache" % BUILDDIR)
|
|
||||||
if coverage:
|
|
||||||
flags.append(coverage.flag)
|
|
||||||
|
|
||||||
if len(test_list) > 1 and run_parallel > 1:
|
|
||||||
# Populate cache
|
# Populate cache
|
||||||
subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags)
|
subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
|
||||||
|
|
||||||
#Run Tests
|
#Run Tests
|
||||||
max_len_name = len(max(test_list, key=len))
|
all_passed = True
|
||||||
time_sum = 0
|
time_sum = 0
|
||||||
time0 = time.time()
|
time0 = time.time()
|
||||||
job_queue = RPCTestHandler(run_parallel, test_list, flags)
|
|
||||||
|
job_queue = RPCTestHandler(jobs, tests_dir, test_list, flags)
|
||||||
|
|
||||||
|
max_len_name = len(max(test_list, key=len))
|
||||||
results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0]
|
results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0]
|
||||||
all_passed = True
|
|
||||||
for _ in range(len(test_list)):
|
for _ in range(len(test_list)):
|
||||||
(name, stdout, stderr, passed, duration) = job_queue.get_next()
|
(name, stdout, stderr, passed, duration) = job_queue.get_next()
|
||||||
all_passed = all_passed and passed
|
all_passed = all_passed and passed
|
||||||
|
@ -233,8 +250,10 @@ def runtests():
|
||||||
print('\n' + BOLD[1] + name + BOLD[0] + ":")
|
print('\n' + BOLD[1] + name + BOLD[0] + ":")
|
||||||
print('' if passed else stdout + '\n', end='')
|
print('' if passed else stdout + '\n', end='')
|
||||||
print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
|
print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
|
||||||
results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
|
|
||||||
print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
|
print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
|
||||||
|
|
||||||
|
results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
|
||||||
|
|
||||||
results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0]
|
results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0]
|
||||||
print(results)
|
print(results)
|
||||||
print("\nRuntime: %s s" % (int(time.time() - time0)))
|
print("\nRuntime: %s s" % (int(time.time() - time0)))
|
||||||
|
@ -247,15 +266,15 @@ def runtests():
|
||||||
|
|
||||||
sys.exit(not all_passed)
|
sys.exit(not all_passed)
|
||||||
|
|
||||||
|
|
||||||
class RPCTestHandler:
|
class RPCTestHandler:
|
||||||
"""
|
"""
|
||||||
Trigger the testscrips passed in via the list.
|
Trigger the testscrips passed in via the list.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, num_tests_parallel, test_list=None, flags=None):
|
def __init__(self, num_tests_parallel, tests_dir, test_list=None, flags=None):
|
||||||
assert(num_tests_parallel >= 1)
|
assert(num_tests_parallel >= 1)
|
||||||
self.num_jobs = num_tests_parallel
|
self.num_jobs = num_tests_parallel
|
||||||
|
self.tests_dir = tests_dir
|
||||||
self.test_list = test_list
|
self.test_list = test_list
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.num_running = 0
|
self.num_running = 0
|
||||||
|
@ -275,7 +294,7 @@ class RPCTestHandler:
|
||||||
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
|
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
|
||||||
self.jobs.append((t,
|
self.jobs.append((t,
|
||||||
time.time(),
|
time.time(),
|
||||||
subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed,
|
subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed,
|
||||||
universal_newlines=True,
|
universal_newlines=True,
|
||||||
stdout=log_stdout,
|
stdout=log_stdout,
|
||||||
stderr=log_stderr),
|
stderr=log_stderr),
|
||||||
|
@ -340,10 +359,10 @@ class RPCCoverage(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# This is shared from `qa/rpc-tests/test-framework/coverage.py`
|
# This is shared from `qa/rpc-tests/test-framework/coverage.py`
|
||||||
REFERENCE_FILENAME = 'rpc_interface.txt'
|
reference_filename = 'rpc_interface.txt'
|
||||||
COVERAGE_FILE_PREFIX = 'coverage.'
|
coverage_file_prefix = 'coverage.'
|
||||||
|
|
||||||
coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME)
|
coverage_ref_filename = os.path.join(self.dir, reference_filename)
|
||||||
coverage_filenames = set()
|
coverage_filenames = set()
|
||||||
all_cmds = set()
|
all_cmds = set()
|
||||||
covered_cmds = set()
|
covered_cmds = set()
|
||||||
|
@ -356,7 +375,7 @@ class RPCCoverage(object):
|
||||||
|
|
||||||
for root, dirs, files in os.walk(self.dir):
|
for root, dirs, files in os.walk(self.dir):
|
||||||
for filename in files:
|
for filename in files:
|
||||||
if filename.startswith(COVERAGE_FILE_PREFIX):
|
if filename.startswith(coverage_file_prefix):
|
||||||
coverage_filenames.add(os.path.join(root, filename))
|
coverage_filenames.add(os.path.join(root, filename))
|
||||||
|
|
||||||
for filename in coverage_filenames:
|
for filename in coverage_filenames:
|
||||||
|
@ -367,4 +386,4 @@ class RPCCoverage(object):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
runtests()
|
main()
|
||||||
|
|
18
qa/pull-tester/tests_config.ini.in
Normal file
18
qa/pull-tester/tests_config.ini.in
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Copyright (c) 2013-2016 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
# These environment variables are set by the build process and read by
|
||||||
|
# rpc-tests.py
|
||||||
|
|
||||||
|
[environment]
|
||||||
|
SRCDIR=@abs_top_srcdir@
|
||||||
|
BUILDDIR=@abs_top_builddir@
|
||||||
|
EXEEXT=@EXEEXT@
|
||||||
|
|
||||||
|
[components]
|
||||||
|
# Which components are enabled. These are commented out by `configure` if they were disabled when running config.
|
||||||
|
@ENABLE_WALLET_TRUE@ENABLE_WALLET=true
|
||||||
|
@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true
|
||||||
|
@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true
|
||||||
|
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true
|
|
@ -1,14 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# Copyright (c) 2013-2016 The Bitcoin Core developers
|
|
||||||
# Distributed under the MIT software license, see the accompanying
|
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
|
|
||||||
SRCDIR="@abs_top_srcdir@"
|
|
||||||
BUILDDIR="@abs_top_builddir@"
|
|
||||||
EXEEXT="@EXEEXT@"
|
|
||||||
|
|
||||||
# These will turn into comments if they were disabled when configuring.
|
|
||||||
@ENABLE_WALLET_TRUE@ENABLE_WALLET=1
|
|
||||||
@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=1
|
|
||||||
@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=1
|
|
||||||
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=1
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
from test_framework.test_framework import ComparisonTestFramework
|
from test_framework.test_framework import ComparisonTestFramework
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
from test_framework.mininode import ToHex, CTransaction, NetworkThread
|
from test_framework.mininode import ToHex, NetworkThread
|
||||||
from test_framework.blocktools import create_coinbase, create_block
|
from test_framework.blocktools import create_coinbase, create_block
|
||||||
from test_framework.comptool import TestInstance, TestManager
|
from test_framework.comptool import TestInstance, TestManager
|
||||||
from test_framework.script import *
|
from test_framework.script import *
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
from test_framework.script import *
|
|
||||||
from test_framework.mininode import *
|
|
||||||
from test_framework.blocktools import *
|
from test_framework.blocktools import *
|
||||||
|
|
||||||
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
|
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
|
||||||
|
|
|
@ -8,10 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework import blocktools
|
from test_framework import blocktools
|
||||||
from test_framework.mininode import CTransaction
|
from test_framework.mininode import CTransaction
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
from test_framework.util import *
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import time
|
|
||||||
|
|
||||||
# Sequence number that is BIP 125 opt-in and BIP 68-compliant
|
# Sequence number that is BIP 125 opt-in and BIP 68-compliant
|
||||||
BIP125_SEQUENCE_NUMBER = 0xfffffffd
|
BIP125_SEQUENCE_NUMBER = 0xfffffffd
|
||||||
|
|
|
@ -2,54 +2,105 @@
|
||||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
"""Test rescan behavior of importaddress, importpubkey, importprivkey, and
|
||||||
|
importmulti RPCs with different types of keys and rescan options.
|
||||||
|
|
||||||
|
In the first part of the test, node 0 creates an address for each type of
|
||||||
|
import RPC call and sends BTC to it. Then other nodes import the addresses,
|
||||||
|
and the test makes listtransactions and getbalance calls to confirm that the
|
||||||
|
importing node either did or did not execute rescans picking up the send
|
||||||
|
transactions.
|
||||||
|
|
||||||
|
In the second part of the test, node 0 sends more BTC to each address, and the
|
||||||
|
test makes more listtransactions and getbalance calls to confirm that the
|
||||||
|
importing nodes pick up the new transactions regardless of whether rescans
|
||||||
|
happened previously.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal)
|
from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal, set_node_times)
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import enum
|
import enum
|
||||||
import itertools
|
import itertools
|
||||||
import functools
|
|
||||||
|
|
||||||
Call = enum.Enum("Call", "single multi")
|
Call = enum.Enum("Call", "single multi")
|
||||||
Data = enum.Enum("Data", "address pub priv")
|
Data = enum.Enum("Data", "address pub priv")
|
||||||
ImportNode = collections.namedtuple("ImportNode", "rescan")
|
Rescan = enum.Enum("Rescan", "no yes late_timestamp")
|
||||||
|
|
||||||
|
|
||||||
def call_import_rpc(call, data, address, scriptPubKey, pubkey, key, label, node, rescan):
|
class Variant(collections.namedtuple("Variant", "call data rescan prune")):
|
||||||
"""Helper that calls a wallet import RPC on a bitcoin node."""
|
"""Helper for importing one key and verifying scanned transactions."""
|
||||||
watchonly = data != Data.priv
|
|
||||||
if call == Call.single:
|
def do_import(self, timestamp):
|
||||||
if data == Data.address:
|
"""Call one key import RPC."""
|
||||||
response = node.importaddress(address, label, rescan)
|
|
||||||
elif data == Data.pub:
|
if self.call == Call.single:
|
||||||
response = node.importpubkey(pubkey, label, rescan)
|
if self.data == Data.address:
|
||||||
elif data == Data.priv:
|
response, error = try_rpc(self.node.importaddress, self.address["address"], self.label,
|
||||||
response = node.importprivkey(key, label, rescan)
|
self.rescan == Rescan.yes)
|
||||||
|
elif self.data == Data.pub:
|
||||||
|
response, error = try_rpc(self.node.importpubkey, self.address["pubkey"], self.label,
|
||||||
|
self.rescan == Rescan.yes)
|
||||||
|
elif self.data == Data.priv:
|
||||||
|
response, error = try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes)
|
||||||
assert_equal(response, None)
|
assert_equal(response, None)
|
||||||
elif call == Call.multi:
|
assert_equal(error, {'message': 'Rescan is disabled in pruned mode',
|
||||||
response = node.importmulti([{
|
'code': -4} if self.expect_disabled else None)
|
||||||
|
elif self.call == Call.multi:
|
||||||
|
response = self.node.importmulti([{
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address
|
"address": self.address["address"]
|
||||||
},
|
},
|
||||||
"pubkeys": [pubkey] if data == Data.pub else [],
|
"timestamp": timestamp + RESCAN_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
|
||||||
"keys": [key] if data == Data.priv else [],
|
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
|
||||||
"label": label,
|
"keys": [self.key] if self.data == Data.priv else [],
|
||||||
"watchonly": watchonly
|
"label": self.label,
|
||||||
}], {"rescan": rescan})
|
"watchonly": self.data != Data.priv
|
||||||
|
}], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)})
|
||||||
assert_equal(response, [{"success": True}])
|
assert_equal(response, [{"success": True}])
|
||||||
return watchonly
|
|
||||||
|
def check(self, txid=None, amount=None, confirmations=None):
|
||||||
|
"""Verify that getbalance/listtransactions return expected values."""
|
||||||
|
|
||||||
|
balance = self.node.getbalance(self.label, 0, True)
|
||||||
|
assert_equal(balance, self.expected_balance)
|
||||||
|
|
||||||
|
txs = self.node.listtransactions(self.label, 10000, 0, True)
|
||||||
|
assert_equal(len(txs), self.expected_txs)
|
||||||
|
|
||||||
|
if txid is not None:
|
||||||
|
tx, = [tx for tx in txs if tx["txid"] == txid]
|
||||||
|
assert_equal(tx["account"], self.label)
|
||||||
|
assert_equal(tx["address"], self.address["address"])
|
||||||
|
assert_equal(tx["amount"], amount)
|
||||||
|
assert_equal(tx["category"], "receive")
|
||||||
|
assert_equal(tx["label"], self.label)
|
||||||
|
assert_equal(tx["txid"], txid)
|
||||||
|
assert_equal(tx["confirmations"], confirmations)
|
||||||
|
assert_equal("trusted" not in tx, True)
|
||||||
|
if self.data != Data.priv:
|
||||||
|
assert_equal(tx["involvesWatchonly"], True)
|
||||||
|
else:
|
||||||
|
assert_equal("involvesWatchonly" not in tx, True)
|
||||||
|
|
||||||
|
|
||||||
# List of RPCs that import a wallet key or address in various ways.
|
# List of Variants for each way a key or address could be imported.
|
||||||
IMPORT_RPCS = [functools.partial(call_import_rpc, call, data) for call, data in itertools.product(Call, Data)]
|
IMPORT_VARIANTS = [Variant(*variants) for variants in itertools.product(Call, Data, Rescan, (False, True))]
|
||||||
|
|
||||||
# List of bitcoind nodes that will import keys.
|
# List of nodes to import keys to. Half the nodes will have pruning disabled,
|
||||||
IMPORT_NODES = [
|
# half will have it enabled. Different nodes will be used for imports that are
|
||||||
ImportNode(rescan=True),
|
# expected to cause rescans, and imports that are not expected to cause
|
||||||
ImportNode(rescan=False),
|
# rescans, in order to prevent rescans during later imports picking up
|
||||||
]
|
# transactions associated with earlier imports. This makes it easier to keep
|
||||||
|
# track of expected balances and transactions.
|
||||||
|
ImportNode = collections.namedtuple("ImportNode", "prune rescan")
|
||||||
|
IMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True), repeat=2)]
|
||||||
|
|
||||||
|
# Rescans start at the earliest block up to 2 hours before the key timestamp.
|
||||||
|
RESCAN_WINDOW = 2 * 60 * 60
|
||||||
|
|
||||||
|
|
||||||
class ImportRescanTest(BitcoinTestFramework):
|
class ImportRescanTest(BitcoinTestFramework):
|
||||||
|
@ -59,6 +110,10 @@ class ImportRescanTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def setup_network(self):
|
def setup_network(self):
|
||||||
extra_args = [["-debug=1"] for _ in range(self.num_nodes)]
|
extra_args = [["-debug=1"] for _ in range(self.num_nodes)]
|
||||||
|
for i, import_node in enumerate(IMPORT_NODES, 1):
|
||||||
|
if import_node.prune:
|
||||||
|
extra_args[i] += ["-prune=1"]
|
||||||
|
|
||||||
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
|
||||||
for i in range(1, self.num_nodes):
|
for i in range(1, self.num_nodes):
|
||||||
connect_nodes(self.nodes[i], 0)
|
connect_nodes(self.nodes[i], 0)
|
||||||
|
@ -66,89 +121,64 @@ class ImportRescanTest(BitcoinTestFramework):
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Create one transaction on node 0 with a unique amount and label for
|
# Create one transaction on node 0 with a unique amount and label for
|
||||||
# each possible type of wallet import RPC.
|
# each possible type of wallet import RPC.
|
||||||
import_rpc_variants = []
|
for i, variant in enumerate(IMPORT_VARIANTS):
|
||||||
for i, import_rpc in enumerate(IMPORT_RPCS):
|
variant.label = "label {} {}".format(i, variant)
|
||||||
label = "label{}".format(i)
|
variant.address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress(variant.label))
|
||||||
addr = self.nodes[0].validateaddress(self.nodes[0].getnewaddress(label))
|
variant.key = self.nodes[0].dumpprivkey(variant.address["address"])
|
||||||
key = self.nodes[0].dumpprivkey(addr["address"])
|
variant.initial_amount = 25 - (i + 1) / 4.0
|
||||||
amount = 24.9375 - i * .0625
|
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
|
||||||
txid = self.nodes[0].sendtoaddress(addr["address"], amount)
|
|
||||||
import_rpc = functools.partial(import_rpc, addr["address"], addr["scriptPubKey"], addr["pubkey"], key,
|
|
||||||
label)
|
|
||||||
import_rpc_variants.append((import_rpc, label, amount, txid, addr))
|
|
||||||
|
|
||||||
|
# Generate a block containing the initial transactions, then another
|
||||||
|
# block further in the future (past the rescan window).
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
assert_equal(self.nodes[0].getrawmempool(), [])
|
assert_equal(self.nodes[0].getrawmempool(), [])
|
||||||
|
timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
|
||||||
|
set_node_times(self.nodes, timestamp + RESCAN_WINDOW + 1)
|
||||||
|
self.nodes[0].generate(1)
|
||||||
sync_blocks(self.nodes)
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
# For each importing node and variation of wallet import RPC, invoke
|
# For each variation of wallet key import, invoke the import RPC and
|
||||||
# the RPC and check the results from getbalance and listtransactions.
|
# check the results from getbalance and listtransactions.
|
||||||
for node, import_node in zip(self.nodes[1:], IMPORT_NODES):
|
for variant in IMPORT_VARIANTS:
|
||||||
for import_rpc, label, amount, txid, addr in import_rpc_variants:
|
variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single
|
||||||
watchonly = import_rpc(node, import_node.rescan)
|
expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled
|
||||||
|
variant.node = self.nodes[1 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]
|
||||||
balance = node.getbalance(label, 0, True)
|
variant.do_import(timestamp)
|
||||||
if import_node.rescan:
|
if expect_rescan:
|
||||||
assert_equal(balance, amount)
|
variant.expected_balance = variant.initial_amount
|
||||||
|
variant.expected_txs = 1
|
||||||
|
variant.check(variant.initial_txid, variant.initial_amount, 2)
|
||||||
else:
|
else:
|
||||||
assert_equal(balance, 0)
|
variant.expected_balance = 0
|
||||||
|
variant.expected_txs = 0
|
||||||
|
variant.check()
|
||||||
|
|
||||||
txs = node.listtransactions(label, 10000, 0, True)
|
# Create new transactions sending to each address.
|
||||||
if import_node.rescan:
|
|
||||||
assert_equal(len(txs), 1)
|
|
||||||
assert_equal(txs[0]["account"], label)
|
|
||||||
assert_equal(txs[0]["address"], addr["address"])
|
|
||||||
assert_equal(txs[0]["amount"], amount)
|
|
||||||
assert_equal(txs[0]["category"], "receive")
|
|
||||||
assert_equal(txs[0]["label"], label)
|
|
||||||
assert_equal(txs[0]["txid"], txid)
|
|
||||||
assert_equal(txs[0]["confirmations"], 1)
|
|
||||||
assert_equal("trusted" not in txs[0], True)
|
|
||||||
if watchonly:
|
|
||||||
assert_equal(txs[0]["involvesWatchonly"], True)
|
|
||||||
else:
|
|
||||||
assert_equal("involvesWatchonly" not in txs[0], True)
|
|
||||||
else:
|
|
||||||
assert_equal(len(txs), 0)
|
|
||||||
|
|
||||||
# Create spends for all the imported addresses.
|
|
||||||
spend_txids = []
|
|
||||||
fee = self.nodes[0].getnetworkinfo()["relayfee"]
|
fee = self.nodes[0].getnetworkinfo()["relayfee"]
|
||||||
for import_rpc, label, amount, txid, addr in import_rpc_variants:
|
for i, variant in enumerate(IMPORT_VARIANTS):
|
||||||
raw_tx = self.nodes[0].getrawtransaction(txid)
|
variant.sent_amount = 25 - (2 * i + 1) / 8.0
|
||||||
decoded_tx = self.nodes[0].decoderawtransaction(raw_tx)
|
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
|
||||||
input_vout = next(out["n"] for out in decoded_tx["vout"]
|
|
||||||
if out["scriptPubKey"]["addresses"] == [addr["address"]])
|
|
||||||
inputs = [{"txid": txid, "vout": input_vout}]
|
|
||||||
outputs = {self.nodes[0].getnewaddress(): Decimal(amount) - fee}
|
|
||||||
raw_spend_tx = self.nodes[0].createrawtransaction(inputs, outputs)
|
|
||||||
signed_spend_tx = self.nodes[0].signrawtransaction(raw_spend_tx)
|
|
||||||
spend_txid = self.nodes[0].sendrawtransaction(signed_spend_tx["hex"])
|
|
||||||
spend_txids.append(spend_txid)
|
|
||||||
|
|
||||||
|
# Generate a block containing the new transactions.
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
assert_equal(self.nodes[0].getrawmempool(), [])
|
assert_equal(self.nodes[0].getrawmempool(), [])
|
||||||
sync_blocks(self.nodes)
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
# Check the results from getbalance and listtransactions after the spends.
|
# Check the latest results from getbalance and listtransactions.
|
||||||
for node, import_node in zip(self.nodes[1:], IMPORT_NODES):
|
for variant in IMPORT_VARIANTS:
|
||||||
txs = node.listtransactions("*", 10000, 0, True)
|
if not variant.expect_disabled:
|
||||||
for (import_rpc, label, amount, txid, addr), spend_txid in zip(import_rpc_variants, spend_txids):
|
variant.expected_balance += variant.sent_amount
|
||||||
balance = node.getbalance(label, 0, True)
|
variant.expected_txs += 1
|
||||||
spend_tx = [tx for tx in txs if tx["txid"] == spend_txid]
|
variant.check(variant.sent_txid, variant.sent_amount, 1)
|
||||||
if import_node.rescan:
|
|
||||||
assert_equal(balance, amount)
|
|
||||||
assert_equal(len(spend_tx), 1)
|
|
||||||
assert_equal(spend_tx[0]["account"], "")
|
|
||||||
assert_equal(spend_tx[0]["amount"] + spend_tx[0]["fee"], -amount)
|
|
||||||
assert_equal(spend_tx[0]["category"], "send")
|
|
||||||
assert_equal("label" not in spend_tx[0], True)
|
|
||||||
assert_equal(spend_tx[0]["confirmations"], 1)
|
|
||||||
assert_equal("trusted" not in spend_tx[0], True)
|
|
||||||
assert_equal("involvesWatchonly" not in txs[0], True)
|
|
||||||
else:
|
else:
|
||||||
assert_equal(balance, 0)
|
variant.check()
|
||||||
assert_equal(spend_tx, [])
|
|
||||||
|
|
||||||
|
def try_rpc(func, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs), None
|
||||||
|
except JSONRPCException as e:
|
||||||
|
return None, e.error
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -20,6 +20,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
print ("Mining blocks...")
|
print ("Mining blocks...")
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
||||||
|
|
||||||
# keyword definition
|
# keyword definition
|
||||||
PRIV_KEY = 'privkey'
|
PRIV_KEY = 'privkey'
|
||||||
|
@ -52,31 +53,48 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address['address']
|
"address": address['address']
|
||||||
}
|
},
|
||||||
|
"timestamp": "now",
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], True)
|
assert_equal(address_assert['iswatchonly'], True)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
watchonly_address = address['address']
|
||||||
|
watchonly_timestamp = timestamp
|
||||||
|
|
||||||
|
print("Should not import an invalid address")
|
||||||
|
result = self.nodes[1].importmulti([{
|
||||||
|
"scriptPubKey": {
|
||||||
|
"address": "not valid address",
|
||||||
|
},
|
||||||
|
"timestamp": "now",
|
||||||
|
}])
|
||||||
|
assert_equal(result[0]['success'], False)
|
||||||
|
assert_equal(result[0]['error']['code'], -5)
|
||||||
|
assert_equal(result[0]['error']['message'], 'Invalid address')
|
||||||
|
|
||||||
# ScriptPubKey + internal
|
# ScriptPubKey + internal
|
||||||
print("Should import a scriptPubKey with internal flag")
|
print("Should import a scriptPubKey with internal flag")
|
||||||
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"internal": True
|
"internal": True
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], True)
|
assert_equal(address_assert['iswatchonly'], True)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
# ScriptPubKey + !internal
|
# ScriptPubKey + !internal
|
||||||
print("Should not import a scriptPubKey without internal flag")
|
print("Should not import a scriptPubKey without internal flag")
|
||||||
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": address['scriptPubKey']
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], False)
|
assert_equal(result[0]['success'], False)
|
||||||
assert_equal(result[0]['error']['code'], -8)
|
assert_equal(result[0]['error']['code'], -8)
|
||||||
|
@ -84,6 +102,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
|
|
||||||
# Address + Public key + !Internal
|
# Address + Public key + !Internal
|
||||||
|
@ -93,12 +112,14 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address['address']
|
"address": address['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"pubkeys": [ address['pubkey'] ]
|
"pubkeys": [ address['pubkey'] ]
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], True)
|
assert_equal(address_assert['iswatchonly'], True)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
|
|
||||||
# ScriptPubKey + Public key + internal
|
# ScriptPubKey + Public key + internal
|
||||||
|
@ -106,6 +127,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
request = [{
|
request = [{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"pubkeys": [ address['pubkey'] ],
|
"pubkeys": [ address['pubkey'] ],
|
||||||
"internal": True
|
"internal": True
|
||||||
}]
|
}]
|
||||||
|
@ -114,12 +136,14 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], True)
|
assert_equal(address_assert['iswatchonly'], True)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
# ScriptPubKey + Public key + !internal
|
# ScriptPubKey + Public key + !internal
|
||||||
print("Should not import a scriptPubKey without internal and with public key")
|
print("Should not import a scriptPubKey without internal and with public key")
|
||||||
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
request = [{
|
request = [{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"pubkeys": [ address['pubkey'] ]
|
"pubkeys": [ address['pubkey'] ]
|
||||||
}]
|
}]
|
||||||
result = self.nodes[1].importmulti(request)
|
result = self.nodes[1].importmulti(request)
|
||||||
|
@ -129,6 +153,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
# Address + Private key + !watchonly
|
# Address + Private key + !watchonly
|
||||||
print("Should import an address with private key")
|
print("Should import an address with private key")
|
||||||
|
@ -137,12 +162,14 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address['address']
|
"address": address['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], True)
|
assert_equal(address_assert['ismine'], True)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
# Address + Private key + watchonly
|
# Address + Private key + watchonly
|
||||||
print("Should not import an address with private key and with watchonly")
|
print("Should not import an address with private key and with watchonly")
|
||||||
|
@ -151,6 +178,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address['address']
|
"address": address['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
|
||||||
"watchonly": True
|
"watchonly": True
|
||||||
}])
|
}])
|
||||||
|
@ -160,12 +188,14 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
# ScriptPubKey + Private key + internal
|
# ScriptPubKey + Private key + internal
|
||||||
print("Should import a scriptPubKey with internal and with private key")
|
print("Should import a scriptPubKey with internal and with private key")
|
||||||
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
|
||||||
"internal": True
|
"internal": True
|
||||||
}])
|
}])
|
||||||
|
@ -173,12 +203,14 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], True)
|
assert_equal(address_assert['ismine'], True)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
# ScriptPubKey + Private key + !internal
|
# ScriptPubKey + Private key + !internal
|
||||||
print("Should not import a scriptPubKey without internal and with private key")
|
print("Should not import a scriptPubKey without internal and with private key")
|
||||||
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], False)
|
assert_equal(result[0]['success'], False)
|
||||||
|
@ -187,6 +219,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
|
|
||||||
# P2SH address
|
# P2SH address
|
||||||
|
@ -197,18 +230,21 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
self.nodes[1].generate(100)
|
self.nodes[1].generate(100)
|
||||||
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
||||||
transaction = self.nodes[1].gettransaction(transactionid)
|
transaction = self.nodes[1].gettransaction(transactionid)
|
||||||
|
|
||||||
print("Should import a p2sh")
|
print("Should import a p2sh")
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": multi_sig_script['address']
|
"address": multi_sig_script['address']
|
||||||
}
|
},
|
||||||
|
"timestamp": "now",
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
||||||
assert_equal(address_assert['isscript'], True)
|
assert_equal(address_assert['isscript'], True)
|
||||||
assert_equal(address_assert['iswatchonly'], True)
|
assert_equal(address_assert['iswatchonly'], True)
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
||||||
assert_equal(p2shunspent['spendable'], False)
|
assert_equal(p2shunspent['spendable'], False)
|
||||||
assert_equal(p2shunspent['solvable'], False)
|
assert_equal(p2shunspent['solvable'], False)
|
||||||
|
@ -222,6 +258,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
self.nodes[1].generate(100)
|
self.nodes[1].generate(100)
|
||||||
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
||||||
transaction = self.nodes[1].gettransaction(transactionid)
|
transaction = self.nodes[1].gettransaction(transactionid)
|
||||||
|
|
||||||
print("Should import a p2sh with respective redeem script")
|
print("Should import a p2sh with respective redeem script")
|
||||||
|
@ -229,9 +266,12 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": multi_sig_script['address']
|
"address": multi_sig_script['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"redeemscript": multi_sig_script['redeemScript']
|
"redeemscript": multi_sig_script['redeemScript']
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
|
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
||||||
assert_equal(p2shunspent['spendable'], False)
|
assert_equal(p2shunspent['spendable'], False)
|
||||||
|
@ -246,6 +286,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
self.nodes[1].generate(100)
|
self.nodes[1].generate(100)
|
||||||
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
||||||
transaction = self.nodes[1].gettransaction(transactionid)
|
transaction = self.nodes[1].gettransaction(transactionid)
|
||||||
|
|
||||||
print("Should import a p2sh with respective redeem script and private keys")
|
print("Should import a p2sh with respective redeem script and private keys")
|
||||||
|
@ -253,10 +294,13 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": multi_sig_script['address']
|
"address": multi_sig_script['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"redeemscript": multi_sig_script['redeemScript'],
|
"redeemscript": multi_sig_script['redeemScript'],
|
||||||
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])]
|
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])]
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], True)
|
assert_equal(result[0]['success'], True)
|
||||||
|
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
||||||
|
assert_equal(address_assert['timestamp'], timestamp)
|
||||||
|
|
||||||
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
||||||
assert_equal(p2shunspent['spendable'], False)
|
assert_equal(p2shunspent['spendable'], False)
|
||||||
|
@ -277,6 +321,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": multi_sig_script['address']
|
"address": multi_sig_script['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"redeemscript": multi_sig_script['redeemScript'],
|
"redeemscript": multi_sig_script['redeemScript'],
|
||||||
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])],
|
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])],
|
||||||
"watchonly": True
|
"watchonly": True
|
||||||
|
@ -294,6 +339,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address['address']
|
"address": address['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"pubkeys": [ address2['pubkey'] ]
|
"pubkeys": [ address2['pubkey'] ]
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], False)
|
assert_equal(result[0]['success'], False)
|
||||||
|
@ -302,6 +348,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
|
|
||||||
# ScriptPubKey + Public key + internal + Wrong pubkey
|
# ScriptPubKey + Public key + internal + Wrong pubkey
|
||||||
|
@ -310,6 +357,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
request = [{
|
request = [{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"pubkeys": [ address2['pubkey'] ],
|
"pubkeys": [ address2['pubkey'] ],
|
||||||
"internal": True
|
"internal": True
|
||||||
}]
|
}]
|
||||||
|
@ -320,6 +368,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
|
|
||||||
# Address + Private key + !watchonly + Wrong private key
|
# Address + Private key + !watchonly + Wrong private key
|
||||||
|
@ -330,6 +379,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
"scriptPubKey": {
|
"scriptPubKey": {
|
||||||
"address": address['address']
|
"address": address['address']
|
||||||
},
|
},
|
||||||
|
"timestamp": "now",
|
||||||
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ]
|
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ]
|
||||||
}])
|
}])
|
||||||
assert_equal(result[0]['success'], False)
|
assert_equal(result[0]['success'], False)
|
||||||
|
@ -338,6 +388,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
|
|
||||||
# ScriptPubKey + Private key + internal + Wrong private key
|
# ScriptPubKey + Private key + internal + Wrong private key
|
||||||
|
@ -346,6 +397,7 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
||||||
result = self.nodes[1].importmulti([{
|
result = self.nodes[1].importmulti([{
|
||||||
"scriptPubKey": address['scriptPubKey'],
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "now",
|
||||||
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ],
|
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ],
|
||||||
"internal": True
|
"internal": True
|
||||||
}])
|
}])
|
||||||
|
@ -355,6 +407,28 @@ class ImportMultiTest (BitcoinTestFramework):
|
||||||
address_assert = self.nodes[1].validateaddress(address['address'])
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
||||||
assert_equal(address_assert['iswatchonly'], False)
|
assert_equal(address_assert['iswatchonly'], False)
|
||||||
assert_equal(address_assert['ismine'], False)
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal('timestamp' in address_assert, False)
|
||||||
|
|
||||||
|
# restart nodes to check for proper serialization/deserialization of watch only address
|
||||||
|
stop_nodes(self.nodes)
|
||||||
|
self.nodes = start_nodes(2, self.options.tmpdir)
|
||||||
|
address_assert = self.nodes[1].validateaddress(watchonly_address)
|
||||||
|
assert_equal(address_assert['iswatchonly'], True)
|
||||||
|
assert_equal(address_assert['ismine'], False)
|
||||||
|
assert_equal(address_assert['timestamp'], watchonly_timestamp);
|
||||||
|
|
||||||
|
# Bad or missing timestamps
|
||||||
|
print("Should throw on invalid or missing timestamp values")
|
||||||
|
assert_raises_message(JSONRPCException, 'Missing required timestamp field for key',
|
||||||
|
self.nodes[1].importmulti, [{
|
||||||
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
}])
|
||||||
|
assert_raises_message(JSONRPCException, 'Expected number or "now" timestamp value for key. got type string',
|
||||||
|
self.nodes[1].importmulti, [{
|
||||||
|
"scriptPubKey": address['scriptPubKey'],
|
||||||
|
"timestamp": "",
|
||||||
|
}])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
ImportMultiTest ().main ()
|
ImportMultiTest ().main ()
|
||||||
|
|
|
@ -7,7 +7,6 @@ from test_framework.mininode import *
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
|
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
|
||||||
from test_framework.siphash import siphash256
|
|
||||||
from test_framework.script import CScript, OP_TRUE
|
from test_framework.script import CScript, OP_TRUE
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -398,7 +398,7 @@ class FullBlockTest(ComparisonTestFramework):
|
||||||
|
|
||||||
# Extend the b26 chain to make sure bitcoind isn't accepting b26
|
# Extend the b26 chain to make sure bitcoind isn't accepting b26
|
||||||
b27 = block(27, spend=out[7])
|
b27 = block(27, spend=out[7])
|
||||||
yield rejected(RejectResult(16, b'bad-prevblk'))
|
yield rejected(RejectResult(0, b'bad-prevblk'))
|
||||||
|
|
||||||
# Now try a too-large-coinbase script
|
# Now try a too-large-coinbase script
|
||||||
tip(15)
|
tip(15)
|
||||||
|
@ -410,7 +410,7 @@ class FullBlockTest(ComparisonTestFramework):
|
||||||
|
|
||||||
# Extend the b28 chain to make sure bitcoind isn't accepting b28
|
# Extend the b28 chain to make sure bitcoind isn't accepting b28
|
||||||
b29 = block(29, spend=out[7])
|
b29 = block(29, spend=out[7])
|
||||||
yield rejected(RejectResult(16, b'bad-prevblk'))
|
yield rejected(RejectResult(0, b'bad-prevblk'))
|
||||||
|
|
||||||
# b30 has a max-sized coinbase scriptSig.
|
# b30 has a max-sized coinbase scriptSig.
|
||||||
tip(23)
|
tip(23)
|
||||||
|
|
145
qa/rpc-tests/p2p-leaktests.py
Executable file
145
qa/rpc-tests/p2p-leaktests.py
Executable file
|
@ -0,0 +1,145 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2017 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
from test_framework.mininode import *
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import *
|
||||||
|
|
||||||
|
'''
|
||||||
|
Test for message sending before handshake completion
|
||||||
|
|
||||||
|
A node should never send anything other than VERSION/VERACK/REJECT until it's
|
||||||
|
received a VERACK.
|
||||||
|
|
||||||
|
This test connects to a node and sends it a few messages, trying to intice it
|
||||||
|
into sending us something it shouldn't.
|
||||||
|
'''
|
||||||
|
|
||||||
|
banscore = 10
|
||||||
|
|
||||||
|
class CLazyNode(NodeConnCB):
|
||||||
|
def __init__(self):
|
||||||
|
self.connection = None
|
||||||
|
self.unexpected_msg = False
|
||||||
|
self.connected = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def add_connection(self, conn):
|
||||||
|
self.connection = conn
|
||||||
|
|
||||||
|
def send_message(self, message):
|
||||||
|
self.connection.send_message(message)
|
||||||
|
|
||||||
|
def bad_message(self, message):
|
||||||
|
self.unexpected_msg = True
|
||||||
|
print("should not have received message: %s" % message.command)
|
||||||
|
|
||||||
|
def on_open(self, conn):
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
def on_version(self, conn, message): self.bad_message(message)
|
||||||
|
def on_verack(self, conn, message): self.bad_message(message)
|
||||||
|
def on_reject(self, conn, message): self.bad_message(message)
|
||||||
|
def on_inv(self, conn, message): self.bad_message(message)
|
||||||
|
def on_addr(self, conn, message): self.bad_message(message)
|
||||||
|
def on_alert(self, conn, message): self.bad_message(message)
|
||||||
|
def on_getdata(self, conn, message): self.bad_message(message)
|
||||||
|
def on_getblocks(self, conn, message): self.bad_message(message)
|
||||||
|
def on_tx(self, conn, message): self.bad_message(message)
|
||||||
|
def on_block(self, conn, message): self.bad_message(message)
|
||||||
|
def on_getaddr(self, conn, message): self.bad_message(message)
|
||||||
|
def on_headers(self, conn, message): self.bad_message(message)
|
||||||
|
def on_getheaders(self, conn, message): self.bad_message(message)
|
||||||
|
def on_ping(self, conn, message): self.bad_message(message)
|
||||||
|
def on_mempool(self, conn): self.bad_message(message)
|
||||||
|
def on_pong(self, conn, message): self.bad_message(message)
|
||||||
|
def on_feefilter(self, conn, message): self.bad_message(message)
|
||||||
|
def on_sendheaders(self, conn, message): self.bad_message(message)
|
||||||
|
def on_sendcmpct(self, conn, message): self.bad_message(message)
|
||||||
|
def on_cmpctblock(self, conn, message): self.bad_message(message)
|
||||||
|
def on_getblocktxn(self, conn, message): self.bad_message(message)
|
||||||
|
def on_blocktxn(self, conn, message): self.bad_message(message)
|
||||||
|
|
||||||
|
# Node that never sends a version. We'll use this to send a bunch of messages
|
||||||
|
# anyway, and eventually get disconnected.
|
||||||
|
class CNodeNoVersionBan(CLazyNode):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# send a bunch of veracks without sending a message. This should get us disconnected.
|
||||||
|
# NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
|
||||||
|
def on_open(self, conn):
|
||||||
|
super().on_open(conn)
|
||||||
|
for i in range(banscore):
|
||||||
|
self.send_message(msg_verack())
|
||||||
|
|
||||||
|
def on_reject(self, conn, message): pass
|
||||||
|
|
||||||
|
# Node that never sends a version. This one just sits idle and hopes to receive
|
||||||
|
# any message (it shouldn't!)
|
||||||
|
class CNodeNoVersionIdle(CLazyNode):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# Node that sends a version but not a verack.
|
||||||
|
class CNodeNoVerackIdle(CLazyNode):
|
||||||
|
def __init__(self):
|
||||||
|
self.version_received = False
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def on_reject(self, conn, message): pass
|
||||||
|
def on_verack(self, conn, message): pass
|
||||||
|
# When version is received, don't reply with a verack. Instead, see if the
|
||||||
|
# node will give us a message that it shouldn't. This is not an exhaustive
|
||||||
|
# list!
|
||||||
|
def on_version(self, conn, message):
|
||||||
|
self.version_received = True
|
||||||
|
conn.send_message(msg_ping())
|
||||||
|
conn.send_message(msg_getaddr())
|
||||||
|
|
||||||
|
class P2PLeakTest(BitcoinTestFramework):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.num_nodes = 1
|
||||||
|
def setup_network(self):
|
||||||
|
extra_args = [['-debug', '-banscore='+str(banscore)]
|
||||||
|
for i in range(self.num_nodes)]
|
||||||
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
no_version_bannode = CNodeNoVersionBan()
|
||||||
|
no_version_idlenode = CNodeNoVersionIdle()
|
||||||
|
no_verack_idlenode = CNodeNoVerackIdle()
|
||||||
|
|
||||||
|
connections = []
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False))
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False))
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode))
|
||||||
|
no_version_bannode.add_connection(connections[0])
|
||||||
|
no_version_idlenode.add_connection(connections[1])
|
||||||
|
no_verack_idlenode.add_connection(connections[2])
|
||||||
|
|
||||||
|
NetworkThread().start() # Start up network handling in another thread
|
||||||
|
|
||||||
|
assert(wait_until(lambda: no_version_bannode.connected and no_version_idlenode.connected and no_verack_idlenode.version_received, timeout=10))
|
||||||
|
|
||||||
|
# Mine a block and make sure that it's not sent to the connected nodes
|
||||||
|
self.nodes[0].generate(1)
|
||||||
|
|
||||||
|
#Give the node enough time to possibly leak out a message
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
#This node should have been banned
|
||||||
|
assert(no_version_bannode.connection.state == "closed")
|
||||||
|
|
||||||
|
[conn.disconnect_node() for conn in connections]
|
||||||
|
|
||||||
|
# Make sure no unexpected messages came in
|
||||||
|
assert(no_version_bannode.unexpected_msg == False)
|
||||||
|
assert(no_version_idlenode.unexpected_msg == False)
|
||||||
|
assert(no_verack_idlenode.unexpected_msg == False)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
P2PLeakTest().main()
|
103
qa/rpc-tests/p2p-timeouts.py
Executable file
103
qa/rpc-tests/p2p-timeouts.py
Executable file
|
@ -0,0 +1,103 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
""" TimeoutsTest -- test various net timeouts (only in extended tests)
|
||||||
|
|
||||||
|
- Create three bitcoind nodes:
|
||||||
|
|
||||||
|
no_verack_node - we never send a verack in response to their version
|
||||||
|
no_version_node - we never send a version (only a ping)
|
||||||
|
no_send_node - we never send any P2P message.
|
||||||
|
|
||||||
|
- Start all three nodes
|
||||||
|
- Wait 1 second
|
||||||
|
- Assert that we're connected
|
||||||
|
- Send a ping to no_verack_node and no_version_node
|
||||||
|
- Wait 30 seconds
|
||||||
|
- Assert that we're still connected
|
||||||
|
- Send a ping to no_verack_node and no_version_node
|
||||||
|
- Wait 31 seconds
|
||||||
|
- Assert that we're no longer connected (timeout to receive version/verack is 60 seconds)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from test_framework.mininode import *
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import *
|
||||||
|
|
||||||
|
class TestNode(SingleNodeConnCB):
|
||||||
|
def __init__(self):
|
||||||
|
SingleNodeConnCB.__init__(self)
|
||||||
|
self.connected = False
|
||||||
|
self.received_version = False
|
||||||
|
|
||||||
|
def on_open(self, conn):
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
def on_close(self, conn):
|
||||||
|
self.connected = False
|
||||||
|
|
||||||
|
def on_version(self, conn, message):
|
||||||
|
# Don't send a verack in response
|
||||||
|
self.received_version = True
|
||||||
|
|
||||||
|
class TimeoutsTest(BitcoinTestFramework):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setup_clean_chain = True
|
||||||
|
self.num_nodes = 1
|
||||||
|
|
||||||
|
def setup_network(self):
|
||||||
|
self.nodes = []
|
||||||
|
|
||||||
|
# Start up node0 to be a version 1, pre-segwit node.
|
||||||
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
|
||||||
|
[["-debug", "-logtimemicros=1"]])
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
# Setup the p2p connections and start up the network thread.
|
||||||
|
self.no_verack_node = TestNode() # never send verack
|
||||||
|
self.no_version_node = TestNode() # never send version (just ping)
|
||||||
|
self.no_send_node = TestNode() # never send anything
|
||||||
|
|
||||||
|
connections = []
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_verack_node))
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_version_node, send_version=False))
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_send_node, send_version=False))
|
||||||
|
self.no_verack_node.add_connection(connections[0])
|
||||||
|
self.no_version_node.add_connection(connections[1])
|
||||||
|
self.no_send_node.add_connection(connections[2])
|
||||||
|
|
||||||
|
NetworkThread().start() # Start up network handling in another thread
|
||||||
|
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
assert(self.no_verack_node.connected)
|
||||||
|
assert(self.no_version_node.connected)
|
||||||
|
assert(self.no_send_node.connected)
|
||||||
|
|
||||||
|
ping_msg = msg_ping()
|
||||||
|
connections[0].send_message(ping_msg)
|
||||||
|
connections[1].send_message(ping_msg)
|
||||||
|
|
||||||
|
sleep(30)
|
||||||
|
|
||||||
|
assert(self.no_verack_node.received_version)
|
||||||
|
|
||||||
|
assert(self.no_verack_node.connected)
|
||||||
|
assert(self.no_version_node.connected)
|
||||||
|
assert(self.no_send_node.connected)
|
||||||
|
|
||||||
|
connections[0].send_message(ping_msg)
|
||||||
|
connections[1].send_message(ping_msg)
|
||||||
|
|
||||||
|
sleep(31)
|
||||||
|
|
||||||
|
assert(not self.no_verack_node.connected)
|
||||||
|
assert(not self.no_version_node.connected)
|
||||||
|
assert(not self.no_send_node.connected)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
TimeoutsTest().main()
|
|
@ -3,17 +3,11 @@
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.authproxy import JSONRPCException
|
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
assert_raises_jsonrpc,
|
assert_raises_jsonrpc,
|
||||||
assert_is_hex_string,
|
|
||||||
assert_is_hash_string,
|
|
||||||
start_nodes,
|
start_nodes,
|
||||||
connect_nodes_bi,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -130,10 +130,14 @@ class SegWitTest(BitcoinTestFramework):
|
||||||
print("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
|
print("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
|
||||||
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
||||||
tmpl = self.nodes[0].getblocktemplate({})
|
tmpl = self.nodes[0].getblocktemplate({})
|
||||||
|
assert(tmpl['sizelimit'] == 1000000)
|
||||||
|
assert('weightlimit' not in tmpl)
|
||||||
assert(tmpl['sigoplimit'] == 20000)
|
assert(tmpl['sigoplimit'] == 20000)
|
||||||
assert(tmpl['transactions'][0]['hash'] == txid)
|
assert(tmpl['transactions'][0]['hash'] == txid)
|
||||||
assert(tmpl['transactions'][0]['sigops'] == 2)
|
assert(tmpl['transactions'][0]['sigops'] == 2)
|
||||||
tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
|
tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
|
||||||
|
assert(tmpl['sizelimit'] == 1000000)
|
||||||
|
assert('weightlimit' not in tmpl)
|
||||||
assert(tmpl['sigoplimit'] == 20000)
|
assert(tmpl['sigoplimit'] == 20000)
|
||||||
assert(tmpl['transactions'][0]['hash'] == txid)
|
assert(tmpl['transactions'][0]['hash'] == txid)
|
||||||
assert(tmpl['transactions'][0]['sigops'] == 2)
|
assert(tmpl['transactions'][0]['sigops'] == 2)
|
||||||
|
@ -241,6 +245,8 @@ class SegWitTest(BitcoinTestFramework):
|
||||||
print("Verify sigops are counted in GBT with BIP141 rules after the fork")
|
print("Verify sigops are counted in GBT with BIP141 rules after the fork")
|
||||||
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
||||||
tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
|
tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
|
||||||
|
assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data
|
||||||
|
assert(tmpl['weightlimit'] == 4000000)
|
||||||
assert(tmpl['sigoplimit'] == 80000)
|
assert(tmpl['sigoplimit'] == 80000)
|
||||||
assert(tmpl['transactions'][0]['txid'] == txid)
|
assert(tmpl['transactions'][0]['txid'] == txid)
|
||||||
assert(tmpl['transactions'][0]['sigops'] == 8)
|
assert(tmpl['transactions'][0]['sigops'] == 8)
|
||||||
|
@ -250,6 +256,8 @@ class SegWitTest(BitcoinTestFramework):
|
||||||
try:
|
try:
|
||||||
tmpl = self.nodes[0].getblocktemplate({})
|
tmpl = self.nodes[0].getblocktemplate({})
|
||||||
assert(len(tmpl['transactions']) == 1) # Doesn't include witness tx
|
assert(len(tmpl['transactions']) == 1) # Doesn't include witness tx
|
||||||
|
assert(tmpl['sizelimit'] == 1000000)
|
||||||
|
assert('weightlimit' not in tmpl)
|
||||||
assert(tmpl['sigoplimit'] == 20000)
|
assert(tmpl['sigoplimit'] == 20000)
|
||||||
assert(tmpl['transactions'][0]['hash'] == txid)
|
assert(tmpl['transactions'][0]['hash'] == txid)
|
||||||
assert(tmpl['transactions'][0]['sigops'] == 2)
|
assert(tmpl['transactions'][0]['sigops'] == 2)
|
||||||
|
|
|
@ -1540,6 +1540,7 @@ class NodeConnCB(object):
|
||||||
if conn.ver_send > BIP0031_VERSION:
|
if conn.ver_send > BIP0031_VERSION:
|
||||||
conn.send_message(msg_pong(message.nonce))
|
conn.send_message(msg_pong(message.nonce))
|
||||||
def on_reject(self, conn, message): pass
|
def on_reject(self, conn, message): pass
|
||||||
|
def on_open(self, conn): pass
|
||||||
def on_close(self, conn): pass
|
def on_close(self, conn): pass
|
||||||
def on_mempool(self, conn): pass
|
def on_mempool(self, conn): pass
|
||||||
def on_pong(self, conn, message): pass
|
def on_pong(self, conn, message): pass
|
||||||
|
@ -1614,7 +1615,7 @@ class NodeConn(asyncore.dispatcher):
|
||||||
"regtest": b"\xfa\xbf\xb5\xda", # regtest
|
"regtest": b"\xfa\xbf\xb5\xda", # regtest
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK):
|
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True):
|
||||||
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
|
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
|
||||||
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
|
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
|
||||||
self.dstaddr = dstaddr
|
self.dstaddr = dstaddr
|
||||||
|
@ -1631,6 +1632,7 @@ class NodeConn(asyncore.dispatcher):
|
||||||
self.disconnect = False
|
self.disconnect = False
|
||||||
self.nServices = 0
|
self.nServices = 0
|
||||||
|
|
||||||
|
if send_version:
|
||||||
# stuff version msg into sendbuf
|
# stuff version msg into sendbuf
|
||||||
vt = msg_version()
|
vt = msg_version()
|
||||||
vt.nServices = services
|
vt.nServices = services
|
||||||
|
@ -1639,6 +1641,7 @@ class NodeConn(asyncore.dispatcher):
|
||||||
vt.addrFrom.ip = "0.0.0.0"
|
vt.addrFrom.ip = "0.0.0.0"
|
||||||
vt.addrFrom.port = 0
|
vt.addrFrom.port = 0
|
||||||
self.send_message(vt, True)
|
self.send_message(vt, True)
|
||||||
|
|
||||||
print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \
|
print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \
|
||||||
+ str(dstport))
|
+ str(dstport))
|
||||||
|
|
||||||
|
@ -1652,8 +1655,10 @@ class NodeConn(asyncore.dispatcher):
|
||||||
self.log.debug(msg)
|
self.log.debug(msg)
|
||||||
|
|
||||||
def handle_connect(self):
|
def handle_connect(self):
|
||||||
|
if self.state != "connected":
|
||||||
self.show_debug_msg("MiniNode: Connected & Listening: \n")
|
self.show_debug_msg("MiniNode: Connected & Listening: \n")
|
||||||
self.state = "connected"
|
self.state = "connected"
|
||||||
|
self.cb.on_open(self)
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
self.show_debug_msg("MiniNode: Closing Connection to %s:%d... "
|
self.show_debug_msg("MiniNode: Closing Connection to %s:%d... "
|
||||||
|
@ -1681,11 +1686,20 @@ class NodeConn(asyncore.dispatcher):
|
||||||
|
|
||||||
def writable(self):
|
def writable(self):
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
|
pre_connection = self.state == "connecting"
|
||||||
length = len(self.sendbuf)
|
length = len(self.sendbuf)
|
||||||
return (length > 0)
|
return (length > 0 or pre_connection)
|
||||||
|
|
||||||
def handle_write(self):
|
def handle_write(self):
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
|
# asyncore does not expose socket connection, only the first read/write
|
||||||
|
# event, thus we must check connection manually here to know when we
|
||||||
|
# actually connect
|
||||||
|
if self.state == "connecting":
|
||||||
|
self.handle_connect()
|
||||||
|
if not self.writable():
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sent = self.send(self.sendbuf)
|
sent = self.send(self.sendbuf)
|
||||||
except:
|
except:
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
start_nodes,
|
start_nodes,
|
||||||
start_node,
|
|
||||||
assert_equal,
|
assert_equal,
|
||||||
connect_nodes_bi,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,11 +53,7 @@ bool CAddrInfo::IsTerrible(int64_t nNow) const
|
||||||
double CAddrInfo::GetChance(int64_t nNow) const
|
double CAddrInfo::GetChance(int64_t nNow) const
|
||||||
{
|
{
|
||||||
double fChance = 1.0;
|
double fChance = 1.0;
|
||||||
|
int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
|
||||||
int64_t nSinceLastTry = nNow - nLastTry;
|
|
||||||
|
|
||||||
if (nSinceLastTry < 0)
|
|
||||||
nSinceLastTry = 0;
|
|
||||||
|
|
||||||
// deprioritize very recent attempts away
|
// deprioritize very recent attempts away
|
||||||
if (nSinceLastTry < 60 * 10)
|
if (nSinceLastTry < 60 * 10)
|
||||||
|
|
|
@ -97,10 +97,10 @@ public:
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
|
||||||
|
|
||||||
// The best chain should have at least this much work.
|
// The best chain should have at least this much work.
|
||||||
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000002cb971dd56d1c583c20f90");
|
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000003f94d1ad391682fe038bf5");
|
||||||
|
|
||||||
// By default assume that the signatures in ancestors of this block are valid.
|
// By default assume that the signatures in ancestors of this block are valid.
|
||||||
consensus.defaultAssumeValid = uint256S("0x0000000000000000030abc968e1bd635736e880b946085c93152969b9a81a6e2"); //447235
|
consensus.defaultAssumeValid = uint256S("0x00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90"); //453354
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message start string is designed to be unlikely to occur in normal data.
|
* The message start string is designed to be unlikely to occur in normal data.
|
||||||
|
@ -201,10 +201,10 @@ public:
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
|
||||||
|
|
||||||
// The best chain should have at least this much work.
|
// The best chain should have at least this much work.
|
||||||
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000198b4def2baa9338d6");
|
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000001f057509eba81aed91");
|
||||||
|
|
||||||
// By default assume that the signatures in ancestors of this block are valid.
|
// By default assume that the signatures in ancestors of this block are valid.
|
||||||
consensus.defaultAssumeValid = uint256S("0x000000000871ee6842d3648317ccc8a435eb8cc3c2429aee94faff9ba26b05a0"); //1043841
|
consensus.defaultAssumeValid = uint256S("0x00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc"); //1079274
|
||||||
|
|
||||||
pchMessageStart[0] = 0x0b;
|
pchMessageStart[0] = 0x0b;
|
||||||
pchMessageStart[1] = 0x11;
|
pchMessageStart[1] = 0x11;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||||
#define CLIENT_VERSION_MAJOR 0
|
#define CLIENT_VERSION_MAJOR 0
|
||||||
#define CLIENT_VERSION_MINOR 13
|
#define CLIENT_VERSION_MINOR 14
|
||||||
#define CLIENT_VERSION_REVISION 99
|
#define CLIENT_VERSION_REVISION 99
|
||||||
#define CLIENT_VERSION_BUILD 0
|
#define CLIENT_VERSION_BUILD 0
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@ public:
|
||||||
static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
|
static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
|
||||||
|
|
||||||
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
|
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
|
||||||
unsigned char buf[sha.OUTPUT_SIZE];
|
unsigned char buf[CSHA256::OUTPUT_SIZE];
|
||||||
sha.Finalize(buf);
|
sha.Finalize(buf);
|
||||||
sha.Reset().Write(buf, sha.OUTPUT_SIZE).Finalize(hash);
|
sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
CHash256& Write(const unsigned char *data, size_t len) {
|
CHash256& Write(const unsigned char *data, size_t len) {
|
||||||
|
@ -49,9 +49,9 @@ public:
|
||||||
static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;
|
static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;
|
||||||
|
|
||||||
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
|
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
|
||||||
unsigned char buf[sha.OUTPUT_SIZE];
|
unsigned char buf[CSHA256::OUTPUT_SIZE];
|
||||||
sha.Finalize(buf);
|
sha.Finalize(buf);
|
||||||
CRIPEMD160().Write(buf, sha.OUTPUT_SIZE).Finalize(hash);
|
CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
CHash160& Write(const unsigned char *data, size_t len) {
|
CHash160& Write(const unsigned char *data, size_t len) {
|
||||||
|
|
|
@ -112,7 +112,7 @@ static bool multiUserAuthorized(std::string strUserPass)
|
||||||
std::string strSalt = vFields[1];
|
std::string strSalt = vFields[1];
|
||||||
std::string strHash = vFields[2];
|
std::string strHash = vFields[2];
|
||||||
|
|
||||||
unsigned int KEY_SIZE = 32;
|
static const unsigned int KEY_SIZE = 32;
|
||||||
unsigned char out[KEY_SIZE];
|
unsigned char out[KEY_SIZE];
|
||||||
|
|
||||||
CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
|
CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
|
||||||
|
|
|
@ -934,7 +934,7 @@ bool AppInitParameterInteraction()
|
||||||
int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
|
int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
|
||||||
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
|
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
|
||||||
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
|
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
|
||||||
// incremental relay fee sets the minimimum feerate increase necessary for BIP 125 replacement in the mempool
|
// incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
|
||||||
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
|
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
|
||||||
if (IsArgSet("-incrementalrelayfee"))
|
if (IsArgSet("-incrementalrelayfee"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1388,6 +1388,11 @@ void CConnman::ThreadSocketHandler()
|
||||||
LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
|
LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
|
||||||
pnode->fDisconnect = true;
|
pnode->fDisconnect = true;
|
||||||
}
|
}
|
||||||
|
else if (!pnode->fSuccessfullyConnected)
|
||||||
|
{
|
||||||
|
LogPrintf("version handshake timeout from %d\n", pnode->id);
|
||||||
|
pnode->fDisconnect = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -1190,8 +1190,31 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strCommand == NetMsgType::REJECT)
|
||||||
|
{
|
||||||
|
if (fDebug) {
|
||||||
|
try {
|
||||||
|
std::string strMsg; unsigned char ccode; std::string strReason;
|
||||||
|
vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);
|
||||||
|
|
||||||
if (strCommand == NetMsgType::VERSION)
|
std::ostringstream ss;
|
||||||
|
ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
|
||||||
|
|
||||||
|
if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)
|
||||||
|
{
|
||||||
|
uint256 hash;
|
||||||
|
vRecv >> hash;
|
||||||
|
ss << ": hash " << hash.ToString();
|
||||||
|
}
|
||||||
|
LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
|
||||||
|
} catch (const std::ios_base::failure&) {
|
||||||
|
// Avoid feedback loops by preventing reject messages from triggering a new reject message.
|
||||||
|
LogPrint("net", "Unparseable reject message received\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (strCommand == NetMsgType::VERSION)
|
||||||
{
|
{
|
||||||
// Each connection can only send one version message
|
// Each connection can only send one version message
|
||||||
if (pfrom->nVersion != 0)
|
if (pfrom->nVersion != 0)
|
||||||
|
@ -1402,6 +1425,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
pfrom->fSuccessfullyConnected = true;
|
pfrom->fSuccessfullyConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (!pfrom->fSuccessfullyConnected)
|
||||||
|
{
|
||||||
|
// Must have a verack message before anything else
|
||||||
|
LOCK(cs_main);
|
||||||
|
Misbehaving(pfrom->GetId(), 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
else if (strCommand == NetMsgType::ADDR)
|
else if (strCommand == NetMsgType::ADDR)
|
||||||
{
|
{
|
||||||
|
@ -2549,31 +2579,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
pfrom->fRelayTxes = true;
|
pfrom->fRelayTxes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
else if (strCommand == NetMsgType::REJECT)
|
|
||||||
{
|
|
||||||
if (fDebug) {
|
|
||||||
try {
|
|
||||||
std::string strMsg; unsigned char ccode; std::string strReason;
|
|
||||||
vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);
|
|
||||||
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
|
|
||||||
|
|
||||||
if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)
|
|
||||||
{
|
|
||||||
uint256 hash;
|
|
||||||
vRecv >> hash;
|
|
||||||
ss << ": hash " << hash.ToString();
|
|
||||||
}
|
|
||||||
LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
|
|
||||||
} catch (const std::ios_base::failure&) {
|
|
||||||
// Avoid feedback loops by preventing reject messages from triggering a new reject message.
|
|
||||||
LogPrint("net", "Unparseable reject message received\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (strCommand == NetMsgType::FEEFILTER) {
|
else if (strCommand == NetMsgType::FEEFILTER) {
|
||||||
CAmount newFeeFilter = 0;
|
CAmount newFeeFilter = 0;
|
||||||
vRecv >> newFeeFilter;
|
vRecv >> newFeeFilter;
|
||||||
|
@ -2601,6 +2606,36 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_main);
|
||||||
|
CNodeState &state = *State(pnode->GetId());
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CBlockReject& reject, state.rejects) {
|
||||||
|
connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
|
||||||
|
}
|
||||||
|
state.rejects.clear();
|
||||||
|
|
||||||
|
if (state.fShouldBan) {
|
||||||
|
state.fShouldBan = false;
|
||||||
|
if (pnode->fWhitelisted)
|
||||||
|
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString());
|
||||||
|
else if (pnode->fAddnode)
|
||||||
|
LogPrintf("Warning: not punishing addnoded peer %s!\n", pnode->addr.ToString());
|
||||||
|
else {
|
||||||
|
pnode->fDisconnect = true;
|
||||||
|
if (pnode->addr.IsLocal())
|
||||||
|
LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connman.Ban(pnode->addr, BanReasonNodeMisbehaving);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
|
bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
|
||||||
{
|
{
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
|
@ -2711,8 +2746,12 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
|
||||||
PrintExceptionContinue(NULL, "ProcessMessages()");
|
PrintExceptionContinue(NULL, "ProcessMessages()");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fRet)
|
if (!fRet) {
|
||||||
LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id);
|
LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
SendRejectsAndCheckIfBanned(pfrom, connman);
|
||||||
|
|
||||||
return fMoreWork;
|
return fMoreWork;
|
||||||
}
|
}
|
||||||
|
@ -2778,29 +2817,9 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
|
||||||
if (!lockMain)
|
if (!lockMain)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
CNodeState &state = *State(pto->GetId());
|
if (SendRejectsAndCheckIfBanned(pto, connman))
|
||||||
|
|
||||||
BOOST_FOREACH(const CBlockReject& reject, state.rejects)
|
|
||||||
connman.PushMessage(pto, msgMaker.Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
|
|
||||||
state.rejects.clear();
|
|
||||||
|
|
||||||
if (state.fShouldBan) {
|
|
||||||
state.fShouldBan = false;
|
|
||||||
if (pto->fWhitelisted)
|
|
||||||
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
|
|
||||||
else if (pto->fAddnode)
|
|
||||||
LogPrintf("Warning: not punishing addnoded peer %s!\n", pto->addr.ToString());
|
|
||||||
else {
|
|
||||||
pto->fDisconnect = true;
|
|
||||||
if (pto->addr.IsLocal())
|
|
||||||
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
|
|
||||||
else
|
|
||||||
{
|
|
||||||
connman.Ban(pto->addr, BanReasonNodeMisbehaving);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
CNodeState &state = *State(pto->GetId());
|
||||||
}
|
|
||||||
|
|
||||||
// Address refresh broadcast
|
// Address refresh broadcast
|
||||||
int64_t nNow = GetTimeMicros();
|
int64_t nNow = GetTimeMicros();
|
||||||
|
|
|
@ -198,6 +198,14 @@ struct timeval MillisToTimeval(int64_t nTimeout)
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class IntrRecvError {
|
||||||
|
OK,
|
||||||
|
Timeout,
|
||||||
|
Disconnected,
|
||||||
|
NetworkError,
|
||||||
|
Interrupted
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read bytes from socket. This will either read the full number of bytes requested
|
* Read bytes from socket. This will either read the full number of bytes requested
|
||||||
* or return False on error or timeout.
|
* or return False on error or timeout.
|
||||||
|
@ -209,7 +217,7 @@ struct timeval MillisToTimeval(int64_t nTimeout)
|
||||||
*
|
*
|
||||||
* @note This function requires that hSocket is in non-blocking mode.
|
* @note This function requires that hSocket is in non-blocking mode.
|
||||||
*/
|
*/
|
||||||
bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket)
|
static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket)
|
||||||
{
|
{
|
||||||
int64_t curTime = GetTimeMillis();
|
int64_t curTime = GetTimeMillis();
|
||||||
int64_t endTime = curTime + timeout;
|
int64_t endTime = curTime + timeout;
|
||||||
|
@ -222,12 +230,12 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
|
||||||
len -= ret;
|
len -= ret;
|
||||||
data += ret;
|
data += ret;
|
||||||
} else if (ret == 0) { // Unexpected disconnection
|
} else if (ret == 0) { // Unexpected disconnection
|
||||||
return false;
|
return IntrRecvError::Disconnected;
|
||||||
} else { // Other error or blocking
|
} else { // Other error or blocking
|
||||||
int nErr = WSAGetLastError();
|
int nErr = WSAGetLastError();
|
||||||
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
|
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
|
||||||
if (!IsSelectableSocket(hSocket)) {
|
if (!IsSelectableSocket(hSocket)) {
|
||||||
return false;
|
return IntrRecvError::NetworkError;
|
||||||
}
|
}
|
||||||
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
|
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
|
@ -235,17 +243,17 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
|
||||||
FD_SET(hSocket, &fdset);
|
FD_SET(hSocket, &fdset);
|
||||||
int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);
|
int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);
|
||||||
if (nRet == SOCKET_ERROR) {
|
if (nRet == SOCKET_ERROR) {
|
||||||
return false;
|
return IntrRecvError::NetworkError;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return IntrRecvError::NetworkError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (interruptSocks5Recv)
|
if (interruptSocks5Recv)
|
||||||
return false;
|
return IntrRecvError::Interrupted;
|
||||||
curTime = GetTimeMillis();
|
curTime = GetTimeMillis();
|
||||||
}
|
}
|
||||||
return len == 0;
|
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProxyCredentials
|
struct ProxyCredentials
|
||||||
|
@ -272,6 +280,7 @@ std::string Socks5ErrorString(int err)
|
||||||
/** Connect using SOCKS5 (as described in RFC1928) */
|
/** Connect using SOCKS5 (as described in RFC1928) */
|
||||||
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
|
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
|
||||||
{
|
{
|
||||||
|
IntrRecvError recvr;
|
||||||
LogPrint("net", "SOCKS5 connecting %s\n", strDest);
|
LogPrint("net", "SOCKS5 connecting %s\n", strDest);
|
||||||
if (strDest.size() > 255) {
|
if (strDest.size() > 255) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
|
@ -294,7 +303,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||||
return error("Error sending to proxy");
|
return error("Error sending to proxy");
|
||||||
}
|
}
|
||||||
char pchRet1[2];
|
char pchRet1[2];
|
||||||
if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
|
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
|
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
|
||||||
return false;
|
return false;
|
||||||
|
@ -320,7 +329,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||||
}
|
}
|
||||||
LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
|
LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
|
||||||
char pchRetA[2];
|
char pchRetA[2];
|
||||||
if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
|
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
return error("Error reading proxy authentication response");
|
return error("Error reading proxy authentication response");
|
||||||
}
|
}
|
||||||
|
@ -349,9 +358,16 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||||
return error("Error sending to proxy");
|
return error("Error sending to proxy");
|
||||||
}
|
}
|
||||||
char pchRet2[4];
|
char pchRet2[4];
|
||||||
if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) {
|
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
return error("Error reading proxy response");
|
if (recvr == IntrRecvError::Timeout) {
|
||||||
|
/* If a timeout happens here, this effectively means we timed out while connecting
|
||||||
|
* to the remote node. This is very common for Tor, so do not print an
|
||||||
|
* error message. */
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return error("Error while reading proxy response");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (pchRet2[0] != 0x05) {
|
if (pchRet2[0] != 0x05) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
|
@ -370,26 +386,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||||
char pchRet3[256];
|
char pchRet3[256];
|
||||||
switch (pchRet2[3])
|
switch (pchRet2[3])
|
||||||
{
|
{
|
||||||
case 0x01: ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
||||||
case 0x04: ret = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
{
|
{
|
||||||
ret = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
|
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
|
||||||
if (!ret) {
|
if (recvr != IntrRecvError::OK) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
return error("Error reading from proxy");
|
return error("Error reading from proxy");
|
||||||
}
|
}
|
||||||
int nRecv = pchRet3[0];
|
int nRecv = pchRet3[0];
|
||||||
ret = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
|
recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: CloseSocket(hSocket); return error("Error: malformed proxy response");
|
default: CloseSocket(hSocket); return error("Error: malformed proxy response");
|
||||||
}
|
}
|
||||||
if (!ret) {
|
if (recvr != IntrRecvError::OK) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
return error("Error reading from proxy");
|
return error("Error reading from proxy");
|
||||||
}
|
}
|
||||||
if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
|
if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
return error("Error reading from proxy");
|
return error("Error reading from proxy");
|
||||||
}
|
}
|
||||||
|
|
|
@ -518,7 +518,10 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
|
||||||
// Propagate cleared model to child objects
|
// Propagate cleared model to child objects
|
||||||
rpcConsole->setClientModel(nullptr);
|
rpcConsole->setClientModel(nullptr);
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
|
if (walletFrame)
|
||||||
|
{
|
||||||
walletFrame->setClientModel(nullptr);
|
walletFrame->setClientModel(nullptr);
|
||||||
|
}
|
||||||
#endif // ENABLE_WALLET
|
#endif // ENABLE_WALLET
|
||||||
unitDisplayControl->setOptionsModel(nullptr);
|
unitDisplayControl->setOptionsModel(nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,9 +563,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
// after fee
|
// after fee
|
||||||
nAfterFee = nAmount - nPayFee;
|
nAfterFee = std::max<CAmount>(nAmount - nPayFee, 0);
|
||||||
if (nAfterFee < 0)
|
|
||||||
nAfterFee = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// actually update labels
|
// actually update labels
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>674</width>
|
<width>674</width>
|
||||||
<height>363</height>
|
<height>415</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -55,9 +55,6 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="sizeWarningLabel">
|
<widget class="QLabel" name="sizeWarningLabel">
|
||||||
<property name="text">
|
|
||||||
<string>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -203,6 +200,36 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblExplanation1">
|
||||||
|
<property name="text">
|
||||||
|
<string>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblExplanation2">
|
||||||
|
<property name="text">
|
||||||
|
<string>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblExplanation3">
|
||||||
|
<property name="text">
|
||||||
|
<string>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -37,9 +37,7 @@
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
#if BOOST_FILESYSTEM_VERSION >= 3
|
|
||||||
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
|
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
|
||||||
#endif
|
|
||||||
#include <boost/scoped_array.hpp>
|
#include <boost/scoped_array.hpp>
|
||||||
|
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
|
@ -67,9 +65,7 @@
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if BOOST_FILESYSTEM_VERSION >= 3
|
|
||||||
static boost::filesystem::detail::utf8_codecvt_facet utf8;
|
static boost::filesystem::detail::utf8_codecvt_facet utf8;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
extern double NSAppKitVersionNumber;
|
extern double NSAppKitVersionNumber;
|
||||||
|
@ -762,6 +758,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
|
||||||
|
|
||||||
|
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
|
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
@ -824,6 +822,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
#else
|
#else
|
||||||
|
|
||||||
bool GetStartOnSystemStartup() { return false; }
|
bool GetStartOnSystemStartup() { return false; }
|
||||||
|
@ -860,7 +859,6 @@ void setClipboard(const QString& str)
|
||||||
QApplication::clipboard()->setText(str, QClipboard::Selection);
|
QApplication::clipboard()->setText(str, QClipboard::Selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BOOST_FILESYSTEM_VERSION >= 3
|
|
||||||
boost::filesystem::path qstringToBoostPath(const QString &path)
|
boost::filesystem::path qstringToBoostPath(const QString &path)
|
||||||
{
|
{
|
||||||
return boost::filesystem::path(path.toStdString(), utf8);
|
return boost::filesystem::path(path.toStdString(), utf8);
|
||||||
|
@ -870,18 +868,6 @@ QString boostPathToQString(const boost::filesystem::path &path)
|
||||||
{
|
{
|
||||||
return QString::fromStdString(path.string(utf8));
|
return QString::fromStdString(path.string(utf8));
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
#warning Conversion between boost path and QString can use invalid character encoding with boost_filesystem v2 and older
|
|
||||||
boost::filesystem::path qstringToBoostPath(const QString &path)
|
|
||||||
{
|
|
||||||
return boost::filesystem::path(path.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString boostPathToQString(const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
return QString::fromStdString(path.string());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QString formatDurationStr(int secs)
|
QString formatDurationStr(int secs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -124,16 +124,34 @@ Intro::Intro(QWidget *parent) :
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
|
ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
|
||||||
ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
|
ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
|
||||||
|
|
||||||
|
ui->lblExplanation1->setText(ui->lblExplanation1->text()
|
||||||
|
.arg(tr(PACKAGE_NAME))
|
||||||
|
.arg(BLOCK_CHAIN_SIZE)
|
||||||
|
.arg(2009)
|
||||||
|
.arg(tr("Bitcoin"))
|
||||||
|
);
|
||||||
|
ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
|
||||||
|
|
||||||
uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
|
uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
|
||||||
requiredSpace = BLOCK_CHAIN_SIZE;
|
requiredSpace = BLOCK_CHAIN_SIZE;
|
||||||
|
QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time.");
|
||||||
if (pruneTarget) {
|
if (pruneTarget) {
|
||||||
uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
|
uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
|
||||||
if (prunedGBs <= requiredSpace) {
|
if (prunedGBs <= requiredSpace) {
|
||||||
requiredSpace = prunedGBs;
|
requiredSpace = prunedGBs;
|
||||||
|
storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory.");
|
||||||
}
|
}
|
||||||
|
ui->lblExplanation3->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->lblExplanation3->setVisible(false);
|
||||||
}
|
}
|
||||||
requiredSpace += CHAIN_STATE_SIZE;
|
requiredSpace += CHAIN_STATE_SIZE;
|
||||||
ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace));
|
ui->sizeWarningLabel->setText(
|
||||||
|
tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " +
|
||||||
|
storageRequiresMsg.arg(requiredSpace) + " " +
|
||||||
|
tr("The wallet will also be stored in this directory.")
|
||||||
|
);
|
||||||
startThread();
|
startThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,10 @@
|
||||||
<source>Click to enable network activity again.</source>
|
<source>Click to enable network activity again.</source>
|
||||||
<translation>Kliknutím opět umožníš spojení do sítě.</translation>
|
<translation>Kliknutím opět umožníš spojení do sítě.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Syncing Headers (%1%)...</source>
|
||||||
|
<translation>Synchronizuji záhlaví bloků (%1 %)…</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reindexing blocks on disk...</source>
|
<source>Reindexing blocks on disk...</source>
|
||||||
<translation>Vytvářím nový index bloků na disku...</translation>
|
<translation>Vytvářím nový index bloků na disku...</translation>
|
||||||
|
@ -481,6 +485,10 @@
|
||||||
<source>%1 client</source>
|
<source>%1 client</source>
|
||||||
<translation>%1 klient</translation>
|
<translation>%1 klient</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Connecting to peers...</source>
|
||||||
|
<translation>Připojuji se…</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Catching up...</source>
|
<source>Catching up...</source>
|
||||||
<translation>Stahuji...</translation>
|
<translation>Stahuji...</translation>
|
||||||
|
@ -3089,6 +3097,14 @@
|
||||||
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
|
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
|
||||||
<translation>Spustit příkaz, když se objeví transakce týkající se peněženky (%s se v příkazu nahradí za TxID)</translation>
|
<translation>Spustit příkaz, když se objeví transakce týkající se peněženky (%s se v příkazu nahradí za TxID)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
|
||||||
|
<translation>Počet extra transakcí, které se mají držet v paměti pro účely rekonstrukce kompaktních bloků (výchozí: %u)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
|
||||||
|
<translation>Pokud je tenhle blok v řetězci, tak předpokládat, že on i jeho následníci jsou platní, a potenciálně přeskočit ověřování jejich skriptů (0 = ověřovat vše, výchozí: %s, testnet: %s)</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
|
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
|
||||||
<translation>Maximální povolené seřizování času mediánem časů protějšků. Místní vnímání času může být ovlivněno protějšky, a to dopředu nebo dozadu až o toto množství. (výchozí: %u vteřin)</translation>
|
<translation>Maximální povolené seřizování času mediánem časů protějšků. Místní vnímání času může být ovlivněno protějšky, a to dopředu nebo dozadu až o toto množství. (výchozí: %u vteřin)</translation>
|
||||||
|
@ -3105,6 +3121,14 @@
|
||||||
<source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
|
<source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
|
||||||
<translation>Prosíme, zapoj se nebo přispěj, pokud ti %s přijde užitečný. Více informací o programu je na %s.</translation>
|
<translation>Prosíme, zapoj se nebo přispěj, pokud ti %s přijde užitečný. Více informací o programu je na %s.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)</source>
|
||||||
|
<translation>Omezit nároky na úložný prostor prořezáváním (mazáním) starých bloků. Tato volba také umožní použít RPC volání pruneblockchain ke smazání konkrétních bloků a dále automatické prořezávání starých bloků, pokud je zadána cílová velikost souborů s bloky v MiB. Tento režim není slučitelný s -txindex ani -rescan. Upozornění: opětovná změna tohoto nastavení bude vyžadovat nové stažení celého řetězce bloků. (výchozí: 0 = bloky neprořezávat, 1 = povolit ruční prořezávání skrze RPC, >%u = automatické prořezávání bloků tak, aby byla udržena cílová velikost souborů s bloky, v MiB)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
|
||||||
|
<translation>Nastavit nejnižší akceptovatelný poplatek (v %s/kB) pro transakce, které mají být zahrnuty do nových bloků. (výchozí: %s)</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source>
|
<source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source>
|
||||||
<translation>Nastavení počtu vláken pro verifikaci skriptů (%u až %d, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: %d)</translation>
|
<translation>Nastavení počtu vláken pro verifikaci skriptů (%u až %d, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: %d)</translation>
|
||||||
|
|
|
@ -1083,7 +1083,7 @@
|
||||||
<translation>Use a custom data directory:</translation>
|
<translation>Use a custom data directory:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../intro.cpp" line="+89"/>
|
<location filename="../intro.cpp" line="+94"/>
|
||||||
<source>Error: Specified data directory "%1" cannot be created.</source>
|
<source>Error: Specified data directory "%1" cannot be created.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -214,6 +214,10 @@
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>BanTableModel</name>
|
<name>BanTableModel</name>
|
||||||
|
<message>
|
||||||
|
<source>IP/Netmask</source>
|
||||||
|
<translation>IP/Võrgumask</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>BitcoinGUI</name>
|
<name>BitcoinGUI</name>
|
||||||
|
@ -787,6 +791,10 @@
|
||||||
<source>&Window</source>
|
<source>&Window</source>
|
||||||
<translation>&Aken</translation>
|
<translation>&Aken</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Hide tray icon</source>
|
||||||
|
<translation>Peida tegumiriba ikoon</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Show only a tray icon after minimizing the window.</source>
|
<source>Show only a tray icon after minimizing the window.</source>
|
||||||
<translation>Minimeeri systray alale.</translation>
|
<translation>Minimeeri systray alale.</translation>
|
||||||
|
@ -903,10 +911,30 @@
|
||||||
<source>N/A</source>
|
<source>N/A</source>
|
||||||
<translation>N/A</translation>
|
<translation>N/A</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 ms</source>
|
||||||
|
<translation>%1 ms</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%n hour(s)</source>
|
||||||
|
<translation><numerusform>%n tund</numerusform><numerusform>%n tundi</numerusform></translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%n day(s)</source>
|
||||||
|
<translation><numerusform>%n päev</numerusform><numerusform>%n päeva</numerusform></translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%n week(s)</source>
|
||||||
|
<translation><numerusform>%n nädal</numerusform><numerusform>%n nädalat</numerusform></translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 and %2</source>
|
<source>%1 and %2</source>
|
||||||
<translation>%1 ja %2</translation>
|
<translation>%1 ja %2</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%n year(s)</source>
|
||||||
|
<translation><numerusform>%n aasta</numerusform><numerusform>%n aastat</numerusform></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>QObject::QObject</name>
|
<name>QObject::QObject</name>
|
||||||
|
|
|
@ -329,6 +329,10 @@
|
||||||
<source>Click to enable network activity again.</source>
|
<source>Click to enable network activity again.</source>
|
||||||
<translation>Cliquer pour réactiver l'activité réseau.</translation>
|
<translation>Cliquer pour réactiver l'activité réseau.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Syncing Headers (%1%)...</source>
|
||||||
|
<translation>Synchronisation des en-têtes (%1)...</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reindexing blocks on disk...</source>
|
<source>Reindexing blocks on disk...</source>
|
||||||
<translation>Réindexation des blocs sur le disque...</translation>
|
<translation>Réindexation des blocs sur le disque...</translation>
|
||||||
|
|
|
@ -702,10 +702,6 @@
|
||||||
<source>Error</source>
|
<source>Error</source>
|
||||||
<translation>Errore</translation>
|
<translation>Errore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
|
||||||
<source>%n GB of free space available</source>
|
|
||||||
<translation><numerusform>GB di spazio libero disponibile</numerusform><numerusform>%n GB di spazio disponibile</numerusform></translation>
|
|
||||||
</message>
|
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<source>(of %n GB needed)</source>
|
<source>(of %n GB needed)</source>
|
||||||
<translation><numerusform>(di %nGB richiesti)</numerusform><numerusform>(%n GB richiesti)</numerusform></translation>
|
<translation><numerusform>(di %nGB richiesti)</numerusform><numerusform>(%n GB richiesti)</numerusform></translation>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>C&lose</source>
|
<source>C&lose</source>
|
||||||
<translation>Fechar</translation>
|
<translation>&Fechar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Delete the currently selected address from the list</source>
|
<source>Delete the currently selected address from the list</source>
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Delete</source>
|
<source>&Delete</source>
|
||||||
<translation>&Excluir</translation>
|
<translation>E&xcluir</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Choose the address to send coins to</source>
|
<source>Choose the address to send coins to</source>
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
<name>AddressTableModel</name>
|
<name>AddressTableModel</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Label</source>
|
<source>Label</source>
|
||||||
<translation>Rótuo</translation>
|
<translation>Rótulo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Address</source>
|
<source>Address</source>
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no label)</source>
|
<source>(no label)</source>
|
||||||
<translation>(sem rótuo)</translation>
|
<translation>(sem rótulo)</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
<name>BitcoinGUI</name>
|
<name>BitcoinGUI</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Sign &message...</source>
|
<source>Sign &message...</source>
|
||||||
<translation>&Assinar mensagem...</translation>
|
<translation>Assinar &mensagem...</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Synchronizing with network...</source>
|
<source>Synchronizing with network...</source>
|
||||||
|
@ -375,7 +375,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Show / Hide</source>
|
<source>&Show / Hide</source>
|
||||||
<translation>&Exibir/Ocultar</translation>
|
<translation>&Exibir / Ocultar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Show or hide the main Window</source>
|
<source>Show or hide the main Window</source>
|
||||||
|
@ -479,7 +479,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 client</source>
|
<source>%1 client</source>
|
||||||
<translation>%1</translation>
|
<translation>%1 cliente</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Connecting to peers...</source>
|
<source>Connecting to peers...</source>
|
||||||
|
@ -688,7 +688,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no label)</source>
|
<source>(no label)</source>
|
||||||
<translation>(sem rótuo)</translation>
|
<translation>(sem rótulo)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>change from %1 (%2)</source>
|
<source>change from %1 (%2)</source>
|
||||||
|
@ -1360,6 +1360,10 @@
|
||||||
<source>Node/Service</source>
|
<source>Node/Service</source>
|
||||||
<translation>Nó/Serviço</translation>
|
<translation>Nó/Serviço</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>NodeId</source>
|
||||||
|
<translation>ID do nó</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Ping</source>
|
<source>Ping</source>
|
||||||
<translation>Ping</translation>
|
<translation>Ping</translation>
|
||||||
|
@ -1900,7 +1904,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Label</source>
|
<source>Label</source>
|
||||||
<translation>Rótuo</translation>
|
<translation>Rótulo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Message</source>
|
<source>Message</source>
|
||||||
|
@ -1923,7 +1927,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Label</source>
|
<source>Label</source>
|
||||||
<translation>Rótuo</translation>
|
<translation>Rótulo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Message</source>
|
<source>Message</source>
|
||||||
|
@ -1931,7 +1935,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no label)</source>
|
<source>(no label)</source>
|
||||||
<translation>(sem rótuo)</translation>
|
<translation>(sem rótulo)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no message)</source>
|
<source>(no message)</source>
|
||||||
|
@ -2210,7 +2214,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no label)</source>
|
<source>(no label)</source>
|
||||||
<translation>(sem rótuo)</translation>
|
<translation>(sem rótulo)</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -2665,7 +2669,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Label</source>
|
<source>Label</source>
|
||||||
<translation>Rótuo</translation>
|
<translation>Rótulo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<source>Open for %n more block(s)</source>
|
<source>Open for %n more block(s)</source>
|
||||||
|
@ -2741,7 +2745,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no label)</source>
|
<source>(no label)</source>
|
||||||
<translation>(sem rótuo)</translation>
|
<translation>(sem rótulo)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Transaction status. Hover over this field to show number of confirmations.</source>
|
<source>Transaction status. Hover over this field to show number of confirmations.</source>
|
||||||
|
@ -2888,7 +2892,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Label</source>
|
<source>Label</source>
|
||||||
<translation>Rótuo</translation>
|
<translation>Rótulo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Address</source>
|
<source>Address</source>
|
||||||
|
@ -3797,6 +3801,10 @@
|
||||||
<source>Relay non-P2SH multisig (default: %u)</source>
|
<source>Relay non-P2SH multisig (default: %u)</source>
|
||||||
<translation>Retransmitir P2SH não multisig (padrão: %u)</translation>
|
<translation>Retransmitir P2SH não multisig (padrão: %u)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
|
||||||
|
<translation>Ativar opção full-RBF nas transações enviadas (padrão: %u)</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Set key pool size to <n> (default: %u)</source>
|
<source>Set key pool size to <n> (default: %u)</source>
|
||||||
<translation>Defina o tamanho da chave para piscina<n> (padrão: %u)</translation>
|
<translation>Defina o tamanho da chave para piscina<n> (padrão: %u)</translation>
|
||||||
|
@ -3819,7 +3827,7 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Specify pid file (default: %s)</source>
|
<source>Specify pid file (default: %s)</source>
|
||||||
<translation>Especificar aqrquivo pid (padrão: %s)</translation>
|
<translation>Especificar arquivo pid (padrão: %s)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
|
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -481,6 +481,10 @@
|
||||||
<source>%1 client</source>
|
<source>%1 client</source>
|
||||||
<translation>%1 客戶</translation>
|
<translation>%1 客戶</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Connecting to peers...</source>
|
||||||
|
<translation>正在连接到节点……</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Catching up...</source>
|
<source>Catching up...</source>
|
||||||
<translation>更新中...</translation>
|
<translation>更新中...</translation>
|
||||||
|
@ -1927,7 +1931,11 @@
|
||||||
<source>(no amount requested)</source>
|
<source>(no amount requested)</source>
|
||||||
<translation>(无请求金额)</translation>
|
<translation>(无请求金额)</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
<message>
|
||||||
|
<source>Requested</source>
|
||||||
|
<translation>总额</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SendCoinsDialog</name>
|
<name>SendCoinsDialog</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -2178,6 +2186,10 @@
|
||||||
<source>Warning: Unknown change address</source>
|
<source>Warning: Unknown change address</source>
|
||||||
<translation>警告:未知的更改地址</translation>
|
<translation>警告:未知的更改地址</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
|
||||||
|
<translation>你选择的找零地址未被包含在本钱包中,你钱包中的部分或全部金额将被发送至该地址。你确定要这样做吗?</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>(no label)</source>
|
<source>(no label)</source>
|
||||||
<translation>(无标签)</translation>
|
<translation>(无标签)</translation>
|
||||||
|
@ -2459,6 +2471,14 @@
|
||||||
<source>0/unconfirmed, %1</source>
|
<source>0/unconfirmed, %1</source>
|
||||||
<translation>0/未确认,%1</translation>
|
<translation>0/未确认,%1</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>in memory pool</source>
|
||||||
|
<translation>在内存池中</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>not in memory pool</source>
|
||||||
|
<translation>不在内存池中</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>abandoned</source>
|
<source>abandoned</source>
|
||||||
<translation>已抛弃</translation>
|
<translation>已抛弃</translation>
|
||||||
|
@ -3200,6 +3220,10 @@
|
||||||
<source>Use UPnP to map the listening port (default: %u)</source>
|
<source>Use UPnP to map the listening port (default: %u)</source>
|
||||||
<translation>使用UPnp映射监听端口 (默认: %u) </translation>
|
<translation>使用UPnp映射监听端口 (默认: %u) </translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Use the test chain</source>
|
||||||
|
<translation>使用测试链</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>User Agent comment (%s) contains unsafe characters.</source>
|
<source>User Agent comment (%s) contains unsafe characters.</source>
|
||||||
<translation>用户代理评论(%s)包含不安全的字符。</translation>
|
<translation>用户代理评论(%s)包含不安全的字符。</translation>
|
||||||
|
|
|
@ -277,6 +277,9 @@ void OptionsDialog::showRestartWarning(bool fPersistent)
|
||||||
void OptionsDialog::clearStatusLabel()
|
void OptionsDialog::clearStatusLabel()
|
||||||
{
|
{
|
||||||
ui->statusLabel->clear();
|
ui->statusLabel->clear();
|
||||||
|
if (model && model->isRestartRequired()) {
|
||||||
|
showRestartWarning(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsDialog::updateProxyValidationState()
|
void OptionsDialog::updateProxyValidationState()
|
||||||
|
@ -286,7 +289,7 @@ void OptionsDialog::updateProxyValidationState()
|
||||||
if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0))
|
if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0))
|
||||||
{
|
{
|
||||||
setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid
|
setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid
|
||||||
ui->statusLabel->clear();
|
clearStatusLabel();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
#ifndef BITCOIN_QT_PAYMENTREQUESTPLUS_H
|
#ifndef BITCOIN_QT_PAYMENTREQUESTPLUS_H
|
||||||
#define BITCOIN_QT_PAYMENTREQUESTPLUS_H
|
#define BITCOIN_QT_PAYMENTREQUESTPLUS_H
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
#include "paymentrequest.pb.h"
|
#include "paymentrequest.pb.h"
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
|
||||||
const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
|
const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
|
||||||
const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
|
const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
|
||||||
const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
|
const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
|
||||||
// BIP70 max payment request size in bytes (DoS protection)
|
|
||||||
const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
|
|
||||||
|
|
||||||
struct X509StoreDeleter {
|
struct X509StoreDeleter {
|
||||||
void operator()(X509_STORE* b) {
|
void operator()(X509_STORE* b) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ class QUrl;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
// BIP70 max payment request size in bytes (DoS protection)
|
// BIP70 max payment request size in bytes (DoS protection)
|
||||||
extern const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE;
|
static const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
|
||||||
|
|
||||||
class PaymentServer : public QObject
|
class PaymentServer : public QObject
|
||||||
{
|
{
|
||||||
|
|
|
@ -820,7 +820,8 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"pruneblockchain\n"
|
"pruneblockchain\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or to a unix timestamp to prune based on block time.\n"
|
"1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
|
||||||
|
" to prune blocks whose block time is at least 2 hours older than the provided timestamp.\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"n (numeric) Height of the last block pruned.\n"
|
"n (numeric) Height of the last block pruned.\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
|
@ -839,7 +840,8 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
|
||||||
// Height value more than a billion is too high to be a block height, and
|
// Height value more than a billion is too high to be a block height, and
|
||||||
// too low to be a block time (corresponds to timestamp from Sep 2001).
|
// too low to be a block time (corresponds to timestamp from Sep 2001).
|
||||||
if (heightParam > 1000000000) {
|
if (heightParam > 1000000000) {
|
||||||
CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam);
|
// Add a 2 hour buffer to include blocks which might have had old timestamps
|
||||||
|
CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - 7200);
|
||||||
if (!pindex) {
|
if (!pindex) {
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifiy a (method, idx, name) here if the argument is a non-string RPC
|
* Specify a (method, idx, name) here if the argument is a non-string RPC
|
||||||
* argument and needs to be converted from JSON.
|
* argument and needs to be converted from JSON.
|
||||||
*
|
*
|
||||||
* @note Parameter indexes start from 0.
|
* @note Parameter indexes start from 0.
|
||||||
|
|
|
@ -676,8 +676,12 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||||
nSigOpLimit /= WITNESS_SCALE_FACTOR;
|
nSigOpLimit /= WITNESS_SCALE_FACTOR;
|
||||||
}
|
}
|
||||||
result.push_back(Pair("sigoplimit", nSigOpLimit));
|
result.push_back(Pair("sigoplimit", nSigOpLimit));
|
||||||
|
if (fPreSegWit) {
|
||||||
|
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_BASE_SIZE));
|
||||||
|
} else {
|
||||||
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
|
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
|
||||||
result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
|
result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
|
||||||
|
}
|
||||||
result.push_back(Pair("curtime", pblock->GetBlockTime()));
|
result.push_back(Pair("curtime", pblock->GetBlockTime()));
|
||||||
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
|
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
|
||||||
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
|
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
|
||||||
|
|
|
@ -167,6 +167,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
|
||||||
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
|
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
|
||||||
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
|
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
|
||||||
" \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
|
" \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
|
||||||
|
" \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
|
||||||
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
|
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
|
||||||
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
|
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
|
@ -204,10 +205,19 @@ UniValue validateaddress(const JSONRPCRequest& request)
|
||||||
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
|
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
|
||||||
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
|
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
|
||||||
CKeyID keyID;
|
CKeyID keyID;
|
||||||
if (pwalletMain && address.GetKeyID(keyID) && pwalletMain->mapKeyMetadata.count(keyID) && !pwalletMain->mapKeyMetadata[keyID].hdKeypath.empty())
|
if (pwalletMain) {
|
||||||
{
|
const auto& meta = pwalletMain->mapKeyMetadata;
|
||||||
ret.push_back(Pair("hdkeypath", pwalletMain->mapKeyMetadata[keyID].hdKeypath));
|
auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end();
|
||||||
ret.push_back(Pair("hdmasterkeyid", pwalletMain->mapKeyMetadata[keyID].hdMasterKeyID.GetHex()));
|
if (it == meta.end()) {
|
||||||
|
it = meta.find(CScriptID(scriptPubKey));
|
||||||
|
}
|
||||||
|
if (it != meta.end()) {
|
||||||
|
ret.push_back(Pair("timestamp", it->second.nCreateTime));
|
||||||
|
if (!it->second.hdKeypath.empty()) {
|
||||||
|
ret.push_back(Pair("hdkeypath", it->second.hdKeypath));
|
||||||
|
ret.push_back(Pair("hdmasterkeyid", it->second.hdMasterKeyID.GetHex()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -435,7 +445,7 @@ UniValue setmocktime(const JSONRPCRequest& request)
|
||||||
// this could have an effect on mempool time-based eviction, as well as
|
// this could have an effect on mempool time-based eviction, as well as
|
||||||
// IsCurrentForFeeEstimation() and IsInitialBlockDownload().
|
// IsCurrentForFeeEstimation() and IsInitialBlockDownload().
|
||||||
// TODO: figure out the right way to synchronize around mocktime, and
|
// TODO: figure out the right way to synchronize around mocktime, and
|
||||||
// ensure all callsites of GetTime() are accessing this safely.
|
// ensure all call sites of GetTime() are accessing this safely.
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
|
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/iostreams/concepts.hpp>
|
|
||||||
#include <boost/iostreams/stream.hpp>
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/signals2/signal.hpp>
|
#include <boost/signals2/signal.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
|
|
@ -93,8 +93,9 @@ static CSignatureCache signatureCache;
|
||||||
// To be called once in AppInit2/TestingSetup to initialize the signatureCache
|
// To be called once in AppInit2/TestingSetup to initialize the signatureCache
|
||||||
void InitSignatureCache()
|
void InitSignatureCache()
|
||||||
{
|
{
|
||||||
size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
|
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
|
||||||
if (nMaxCacheSize <= 0) return;
|
// setup_bytes creates the minimum possible cache (2 elements).
|
||||||
|
size_t nMaxCacheSize = std::min(std::max((int64_t)0, GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE)), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
|
||||||
size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);
|
size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);
|
||||||
LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to store %zu elements\n",
|
LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to store %zu elements\n",
|
||||||
(nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems);
|
(nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems);
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
// systems). Due to how we count cache size, actual memory usage is slightly
|
// systems). Due to how we count cache size, actual memory usage is slightly
|
||||||
// more (~32.25 MB)
|
// more (~32.25 MB)
|
||||||
static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32;
|
static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32;
|
||||||
|
// Maximum sig cache size allowed
|
||||||
|
static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;
|
||||||
|
|
||||||
class CPubKey;
|
class CPubKey;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
// Tests this internal-to-main.cpp method:
|
// Tests these internal-to-net_processing.cpp methods:
|
||||||
extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
|
extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
|
||||||
extern void EraseOrphansFor(NodeId peer);
|
extern void EraseOrphansFor(NodeId peer);
|
||||||
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
|
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
|
||||||
|
|
|
@ -11,23 +11,5 @@
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
boost::filesystem::path GetTempPath() {
|
boost::filesystem::path GetTempPath() {
|
||||||
#if BOOST_FILESYSTEM_VERSION == 3
|
|
||||||
return boost::filesystem::temp_directory_path();
|
return boost::filesystem::temp_directory_path();
|
||||||
#else
|
|
||||||
// TODO: remove when we don't support filesystem v2 anymore
|
|
||||||
boost::filesystem::path path;
|
|
||||||
#ifdef WIN32
|
|
||||||
char pszPath[MAX_PATH] = "";
|
|
||||||
|
|
||||||
if (GetTempPathA(MAX_PATH, pszPath))
|
|
||||||
path = boost::filesystem::path(pszPath);
|
|
||||||
#else
|
|
||||||
path = boost::filesystem::path("/tmp");
|
|
||||||
#endif
|
|
||||||
if (path.empty() || !boost::filesystem::is_directory(path)) {
|
|
||||||
LogPrintf("GetTempPath(): failed to find temp path\n");
|
|
||||||
return boost::filesystem::path("");
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,7 +395,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
||||||
{
|
{
|
||||||
NotifyEntryAdded(entry.GetSharedTx());
|
NotifyEntryAdded(entry.GetSharedTx());
|
||||||
// Add to memory pool without checking anything.
|
// Add to memory pool without checking anything.
|
||||||
// Used by main.cpp AcceptToMemoryPool(), which DOES do
|
// Used by AcceptToMemoryPool(), which DOES do
|
||||||
// all the appropriate checks.
|
// all the appropriate checks.
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
|
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
|
||||||
|
|
|
@ -214,13 +214,14 @@ void OpenDebugLog()
|
||||||
assert(vMsgsBeforeOpenLog);
|
assert(vMsgsBeforeOpenLog);
|
||||||
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
|
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
|
||||||
fileout = fopen(pathDebug.string().c_str(), "a");
|
fileout = fopen(pathDebug.string().c_str(), "a");
|
||||||
if (fileout) setbuf(fileout, NULL); // unbuffered
|
if (fileout) {
|
||||||
|
setbuf(fileout, NULL); // unbuffered
|
||||||
// dump buffered messages from before we opened the log
|
// dump buffered messages from before we opened the log
|
||||||
while (!vMsgsBeforeOpenLog->empty()) {
|
while (!vMsgsBeforeOpenLog->empty()) {
|
||||||
FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
|
FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
|
||||||
vMsgsBeforeOpenLog->pop_front();
|
vMsgsBeforeOpenLog->pop_front();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete vMsgsBeforeOpenLog;
|
delete vMsgsBeforeOpenLog;
|
||||||
vMsgsBeforeOpenLog = NULL;
|
vMsgsBeforeOpenLog = NULL;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetTimeMicros() and GetTimeMillis() both return the system time, but in
|
* GetTimeMicros() and GetTimeMillis() both return the system time, but in
|
||||||
* different units. GetTime() returns the sytem time in seconds, but also
|
* different units. GetTime() returns the system time in seconds, but also
|
||||||
* supports mocktime, where the time can be specified by the user, eg for
|
* supports mocktime, where the time can be specified by the user, eg for
|
||||||
* testing (eg with the setmocktime rpc, or -mocktime argument).
|
* testing (eg with the setmocktime rpc, or -mocktime argument).
|
||||||
*
|
*
|
||||||
|
|
|
@ -1429,7 +1429,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||||
// Helps prevent CPU exhaustion attacks.
|
// Helps prevent CPU exhaustion attacks.
|
||||||
|
|
||||||
// Skip script verification when connecting blocks under the
|
// Skip script verification when connecting blocks under the
|
||||||
// assumedvalid block. Assuming the assumedvalid block is valid this
|
// assumevalid block. Assuming the assumevalid block is valid this
|
||||||
// is safe because block merkle hashes are still computed and checked,
|
// is safe because block merkle hashes are still computed and checked,
|
||||||
// Of course, if an assumed valid block is invalid due to false scriptSigs
|
// Of course, if an assumed valid block is invalid due to false scriptSigs
|
||||||
// this optimization would allow an invalid chain to be accepted.
|
// this optimization would allow an invalid chain to be accepted.
|
||||||
|
@ -1771,7 +1771,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
|
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
|
||||||
pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
|
pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
|
||||||
// This block is a member of the assumed verified chain and an ancestor of the best header.
|
// This block is a member of the assumed verified chain and an ancestor of the best header.
|
||||||
// The equivalent time check discourages hashpower from extorting the network via DOS attack
|
// The equivalent time check discourages hash power from extorting the network via DOS attack
|
||||||
// into accepting an invalid block through telling users they must manually set assumevalid.
|
// into accepting an invalid block through telling users they must manually set assumevalid.
|
||||||
// Requiring a software change or burying the invalid block, regardless of the setting, makes
|
// Requiring a software change or burying the invalid block, regardless of the setting, makes
|
||||||
// it hard to hide the implication of the demand. This also avoids having release candidates
|
// it hard to hide the implication of the demand. This also avoids having release candidates
|
||||||
|
@ -2486,12 +2486,12 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
||||||
bool fInitialDownload;
|
bool fInitialDownload;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
{ // TODO: Tempoarily ensure that mempool removals are notified before
|
{ // TODO: Temporarily ensure that mempool removals are notified before
|
||||||
// connected transactions. This shouldn't matter, but the abandoned
|
// connected transactions. This shouldn't matter, but the abandoned
|
||||||
// state of transactions in our wallet is currently cleared when we
|
// state of transactions in our wallet is currently cleared when we
|
||||||
// receive another notification and there is a race condition where
|
// receive another notification and there is a race condition where
|
||||||
// notification of a connected conflict might cause an outside process
|
// notification of a connected conflict might cause an outside process
|
||||||
// to abandon a transaction and then have it inadvertantly cleared by
|
// to abandon a transaction and then have it inadvertently cleared by
|
||||||
// the notification that the conflicted transaction was evicted.
|
// the notification that the conflicted transaction was evicted.
|
||||||
MemPoolConflictRemovalTracker mrt(mempool);
|
MemPoolConflictRemovalTracker mrt(mempool);
|
||||||
CBlockIndex *pindexOldTip = chainActive.Tip();
|
CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||||
|
@ -2520,7 +2520,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
||||||
|
|
||||||
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
|
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
|
||||||
|
|
||||||
// Transactions in the connnected block are notified
|
// Transactions in the connected block are notified
|
||||||
for (const auto& pair : connectTrace.blocksConnected) {
|
for (const auto& pair : connectTrace.blocksConnected) {
|
||||||
assert(pair.second);
|
assert(pair.second);
|
||||||
const CBlock& block = *(pair.second);
|
const CBlock& block = *(pair.second);
|
||||||
|
@ -3187,7 +3187,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
|
||||||
}
|
}
|
||||||
if (fNewBlock) *fNewBlock = true;
|
if (fNewBlock) *fNewBlock = true;
|
||||||
|
|
||||||
if (!CheckBlock(block, state, chainparams.GetConsensus(), GetAdjustedTime()) ||
|
if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
|
||||||
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
|
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
|
||||||
if (state.IsInvalid() && !state.CorruptionPossible()) {
|
if (state.IsInvalid() && !state.CorruptionPossible()) {
|
||||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
|
@ -3229,13 +3229,19 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
|
||||||
bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool *fNewBlock)
|
bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool *fNewBlock)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
|
||||||
|
|
||||||
// Store to disk
|
|
||||||
CBlockIndex *pindex = NULL;
|
CBlockIndex *pindex = NULL;
|
||||||
if (fNewBlock) *fNewBlock = false;
|
if (fNewBlock) *fNewBlock = false;
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
|
// Ensure that CheckBlock() passes before calling AcceptBlock, as
|
||||||
|
// belt-and-suspenders.
|
||||||
|
bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
// Store to disk
|
||||||
|
ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
|
||||||
|
}
|
||||||
CheckBlockIndex(chainparams.GetConsensus());
|
CheckBlockIndex(chainparams.GetConsensus());
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
GetMainSignals().BlockChecked(*pblock, state);
|
GetMainSignals().BlockChecked(*pblock, state);
|
||||||
|
@ -4174,7 +4180,7 @@ static const uint64_t MEMPOOL_DUMP_VERSION = 1;
|
||||||
bool LoadMempool(void)
|
bool LoadMempool(void)
|
||||||
{
|
{
|
||||||
int64_t nExpiryTimeout = GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
|
int64_t nExpiryTimeout = GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
|
||||||
FILE* filestr = fopen((GetDataDir() / "mempool.dat").string().c_str(), "r");
|
FILE* filestr = fopen((GetDataDir() / "mempool.dat").string().c_str(), "rb");
|
||||||
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
|
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
|
||||||
if (file.IsNull()) {
|
if (file.IsNull()) {
|
||||||
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
|
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
|
||||||
|
@ -4255,7 +4261,7 @@ void DumpMempool(void)
|
||||||
int64_t mid = GetTimeMicros();
|
int64_t mid = GetTimeMicros();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FILE* filestr = fopen((GetDataDir() / "mempool.dat.new").string().c_str(), "w");
|
FILE* filestr = fopen((GetDataDir() / "mempool.dat.new").string().c_str(), "wb");
|
||||||
if (!filestr) {
|
if (!filestr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ protected:
|
||||||
struct CMainSignals {
|
struct CMainSignals {
|
||||||
/** Notifies listeners of updated block chain tip */
|
/** Notifies listeners of updated block chain tip */
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
|
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
|
||||||
/** A posInBlock value for SyncTransaction calls for tranactions not
|
/** A posInBlock value for SyncTransaction calls for transactions not
|
||||||
* included in connected blocks such as transactions removed from mempool,
|
* included in connected blocks such as transactions removed from mempool,
|
||||||
* accepted to mempool or appearing in disconnected blocks.*/
|
* accepted to mempool or appearing in disconnected blocks.*/
|
||||||
static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1;
|
static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1;
|
||||||
|
|
|
@ -143,7 +143,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||||
|
|
||||||
// whenever a key is imported, we need to scan the whole chain
|
// whenever a key is imported, we need to scan the whole chain
|
||||||
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
pwalletMain->UpdateTimeFirstKey(1);
|
||||||
|
|
||||||
if (fRescan) {
|
if (fRescan) {
|
||||||
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
|
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
|
||||||
|
@ -161,7 +161,7 @@ void ImportScript(const CScript& script, const string& strLabel, bool isRedeemSc
|
||||||
|
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script))
|
if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script, 0 /* nCreateTime */))
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||||
|
|
||||||
if (isRedeemScript) {
|
if (isRedeemScript) {
|
||||||
|
@ -500,8 +500,7 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||||
while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
|
while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
|
||||||
pindex = pindex->pprev;
|
pindex = pindex->pprev;
|
||||||
|
|
||||||
if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
|
pwalletMain->UpdateTimeFirstKey(nTimeBegin);
|
||||||
pwalletMain->nTimeFirstKey = nTimeBegin;
|
|
||||||
|
|
||||||
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
|
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
|
||||||
pwalletMain->ScanForWalletTransactions(pindex);
|
pwalletMain->ScanForWalletTransactions(pindex);
|
||||||
|
@ -576,15 +575,17 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||||
if (!file.is_open())
|
if (!file.is_open())
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
|
||||||
|
|
||||||
std::map<CKeyID, int64_t> mapKeyBirth;
|
std::map<CTxDestination, int64_t> mapKeyBirth;
|
||||||
std::set<CKeyID> setKeyPool;
|
std::set<CKeyID> setKeyPool;
|
||||||
pwalletMain->GetKeyBirthTimes(mapKeyBirth);
|
pwalletMain->GetKeyBirthTimes(mapKeyBirth);
|
||||||
pwalletMain->GetAllReserveKeys(setKeyPool);
|
pwalletMain->GetAllReserveKeys(setKeyPool);
|
||||||
|
|
||||||
// sort time/key pairs
|
// sort time/key pairs
|
||||||
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
|
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
|
||||||
for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
|
for (const auto& entry : mapKeyBirth) {
|
||||||
vKeyBirth.push_back(std::make_pair(it->second, it->first));
|
if (const CKeyID* keyID = boost::get<CKeyID>(&entry.first)) { // set and test
|
||||||
|
vKeyBirth.push_back(std::make_pair(entry.second, *keyID));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mapKeyBirth.clear();
|
mapKeyBirth.clear();
|
||||||
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
||||||
|
@ -640,7 +641,8 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UniValue processImport(const UniValue& data) {
|
UniValue ProcessImport(const UniValue& data, const int64_t timestamp)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
@ -659,7 +661,6 @@ UniValue processImport(const UniValue& data) {
|
||||||
const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false;
|
const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false;
|
||||||
const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
|
const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
|
||||||
const string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
|
const string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
|
||||||
const int64_t& timestamp = data.exists("timestamp") && data["timestamp"].get_int64() > 1 ? data["timestamp"].get_int64() : 1;
|
|
||||||
|
|
||||||
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
|
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
|
||||||
bool isP2SH = strRedeemScript.length() > 0;
|
bool isP2SH = strRedeemScript.length() > 0;
|
||||||
|
@ -671,6 +672,9 @@ UniValue processImport(const UniValue& data) {
|
||||||
|
|
||||||
if (!isScript) {
|
if (!isScript) {
|
||||||
address = CBitcoinAddress(output);
|
address = CBitcoinAddress(output);
|
||||||
|
if (!address.IsValid()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||||
|
}
|
||||||
script = GetScriptForDestination(address.Get());
|
script = GetScriptForDestination(address.Get());
|
||||||
} else {
|
} else {
|
||||||
if (!IsHex(output)) {
|
if (!IsHex(output)) {
|
||||||
|
@ -721,7 +725,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
|
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
if (!pwalletMain->HaveWatchOnly(redeemScript) && !pwalletMain->AddWatchOnly(redeemScript)) {
|
if (!pwalletMain->HaveWatchOnly(redeemScript) && !pwalletMain->AddWatchOnly(redeemScript, timestamp)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,7 +742,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
|
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
if (!pwalletMain->HaveWatchOnly(redeemDestination) && !pwalletMain->AddWatchOnly(redeemDestination)) {
|
if (!pwalletMain->HaveWatchOnly(redeemDestination) && !pwalletMain->AddWatchOnly(redeemDestination, timestamp)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,9 +786,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timestamp < pwalletMain->nTimeFirstKey) {
|
pwalletMain->UpdateTimeFirstKey(timestamp);
|
||||||
pwalletMain->nTimeFirstKey = timestamp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,7 +835,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
|
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
if (!pwalletMain->HaveWatchOnly(pubKeyScript) && !pwalletMain->AddWatchOnly(pubKeyScript)) {
|
if (!pwalletMain->HaveWatchOnly(pubKeyScript) && !pwalletMain->AddWatchOnly(pubKeyScript, timestamp)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,7 +853,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
|
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
if (!pwalletMain->HaveWatchOnly(scriptRawPubKey) && !pwalletMain->AddWatchOnly(scriptRawPubKey)) {
|
if (!pwalletMain->HaveWatchOnly(scriptRawPubKey) && !pwalletMain->AddWatchOnly(scriptRawPubKey, timestamp)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,9 +914,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timestamp < pwalletMain->nTimeFirstKey) {
|
pwalletMain->UpdateTimeFirstKey(timestamp);
|
||||||
pwalletMain->nTimeFirstKey = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
@ -927,7 +927,7 @@ UniValue processImport(const UniValue& data) {
|
||||||
|
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script)) {
|
if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script, timestamp)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,6 +958,20 @@ UniValue processImport(const UniValue& data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t GetImportTimestamp(const UniValue& data, int64_t now)
|
||||||
|
{
|
||||||
|
if (data.exists("timestamp")) {
|
||||||
|
const UniValue& timestamp = data["timestamp"];
|
||||||
|
if (timestamp.isNum()) {
|
||||||
|
return timestamp.get_int64();
|
||||||
|
} else if (timestamp.isStr() && timestamp.get_str() == "now") {
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
|
||||||
|
}
|
||||||
|
throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
|
||||||
|
}
|
||||||
|
|
||||||
UniValue importmulti(const JSONRPCRequest& mainRequest)
|
UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -970,13 +984,18 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||||
" [ (array of json objects)\n"
|
" [ (array of json objects)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"scriptPubKey\": \"<script>\" | { \"address\":\"<address>\" }, (string / json, required) Type of scriptPubKey (string for script, json for address)\n"
|
" \"scriptPubKey\": \"<script>\" | { \"address\":\"<address>\" }, (string / json, required) Type of scriptPubKey (string for script, json for address)\n"
|
||||||
|
" \"timestamp\": timestamp | \"now\" , (integer / string, required) Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n"
|
||||||
|
" or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
|
||||||
|
" key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
|
||||||
|
" \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
|
||||||
|
" 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
|
||||||
|
" creation time of all keys being imported by the importmulti call will be scanned.\n"
|
||||||
" \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
|
" \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
|
||||||
" \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
|
" \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
|
||||||
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
|
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
|
||||||
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n"
|
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n"
|
||||||
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
|
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
|
||||||
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
|
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
|
||||||
" \"timestamp\": 1454686740, (integer, optional, default now) Timestamp\n"
|
|
||||||
" }\n"
|
" }\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
|
@ -1015,6 +1034,12 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
EnsureWalletIsUnlocked();
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
// Verify all timestamps are present before importing any keys.
|
||||||
|
const int64_t now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;
|
||||||
|
for (const UniValue& data : requests.getValues()) {
|
||||||
|
GetImportTimestamp(data, now);
|
||||||
|
}
|
||||||
|
|
||||||
bool fRunScan = false;
|
bool fRunScan = false;
|
||||||
const int64_t minimumTimestamp = 1;
|
const int64_t minimumTimestamp = 1;
|
||||||
int64_t nLowestTimestamp = 0;
|
int64_t nLowestTimestamp = 0;
|
||||||
|
@ -1028,7 +1053,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||||
UniValue response(UniValue::VARR);
|
UniValue response(UniValue::VARR);
|
||||||
|
|
||||||
BOOST_FOREACH (const UniValue& data, requests.getValues()) {
|
BOOST_FOREACH (const UniValue& data, requests.getValues()) {
|
||||||
const UniValue result = processImport(data);
|
const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
|
||||||
|
const UniValue result = ProcessImport(data, timestamp);
|
||||||
response.push_back(result);
|
response.push_back(result);
|
||||||
|
|
||||||
if (!fRescan) {
|
if (!fRescan) {
|
||||||
|
@ -1041,15 +1067,13 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the lowest timestamp.
|
// Get the lowest timestamp.
|
||||||
const int64_t& timestamp = data.exists("timestamp") && data["timestamp"].get_int64() > minimumTimestamp ? data["timestamp"].get_int64() : minimumTimestamp;
|
|
||||||
|
|
||||||
if (timestamp < nLowestTimestamp) {
|
if (timestamp < nLowestTimestamp) {
|
||||||
nLowestTimestamp = timestamp;
|
nLowestTimestamp = timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fRescan && fRunScan && requests.size() && nLowestTimestamp <= chainActive.Tip()->GetBlockTimeMax()) {
|
if (fRescan && fRunScan && requests.size()) {
|
||||||
CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(nLowestTimestamp) : chainActive.Genesis();
|
CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - 7200, 0)) : chainActive.Genesis();
|
||||||
|
|
||||||
if (pindex) {
|
if (pindex) {
|
||||||
pwalletMain->ScanForWalletTransactions(pindex, true);
|
pwalletMain->ScanForWalletTransactions(pindex, true);
|
||||||
|
|
|
@ -2725,7 +2725,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
|
||||||
" be left unchanged from the original. If false, any input sequence numbers in the\n"
|
" be left unchanged from the original. If false, any input sequence numbers in the\n"
|
||||||
" original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
|
" original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
|
||||||
" so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
|
" so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
|
||||||
" still be replacable in practice, for example if it has unconfirmed ancestors which\n"
|
" still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
|
||||||
" are replaceable).\n"
|
" are replaceable).\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
|
|
|
@ -113,8 +113,7 @@ CPubKey CWallet::GenerateNewKey()
|
||||||
assert(secret.VerifyPubKey(pubkey));
|
assert(secret.VerifyPubKey(pubkey));
|
||||||
|
|
||||||
mapKeyMetadata[pubkey.GetID()] = metadata;
|
mapKeyMetadata[pubkey.GetID()] = metadata;
|
||||||
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
|
UpdateTimeFirstKey(nCreationTime);
|
||||||
nTimeFirstKey = nCreationTime;
|
|
||||||
|
|
||||||
if (!AddKeyPubKey(secret, pubkey))
|
if (!AddKeyPubKey(secret, pubkey))
|
||||||
throw std::runtime_error(std::string(__func__) + ": AddKey failed");
|
throw std::runtime_error(std::string(__func__) + ": AddKey failed");
|
||||||
|
@ -207,13 +206,11 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &meta)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||||
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
|
UpdateTimeFirstKey(meta.nCreateTime);
|
||||||
nTimeFirstKey = meta.nCreateTime;
|
mapKeyMetadata[keyID] = meta;
|
||||||
|
|
||||||
mapKeyMetadata[pubkey.GetID()] = meta;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +219,18 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
|
||||||
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWallet::UpdateTimeFirstKey(int64_t nCreateTime)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
|
if (nCreateTime <= 1) {
|
||||||
|
// Cannot determine birthday information, so set the wallet birthday to
|
||||||
|
// the beginning of time.
|
||||||
|
nTimeFirstKey = 1;
|
||||||
|
} else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
|
||||||
|
nTimeFirstKey = nCreateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CWallet::AddCScript(const CScript& redeemScript)
|
bool CWallet::AddCScript(const CScript& redeemScript)
|
||||||
{
|
{
|
||||||
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
||||||
|
@ -247,15 +256,22 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
|
||||||
return CCryptoKeyStore::AddCScript(redeemScript);
|
return CCryptoKeyStore::AddCScript(redeemScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AddWatchOnly(const CScript &dest)
|
bool CWallet::AddWatchOnly(const CScript& dest)
|
||||||
{
|
{
|
||||||
if (!CCryptoKeyStore::AddWatchOnly(dest))
|
if (!CCryptoKeyStore::AddWatchOnly(dest))
|
||||||
return false;
|
return false;
|
||||||
nTimeFirstKey = 1; // No birthday information for watch-only keys.
|
const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];
|
||||||
|
UpdateTimeFirstKey(meta.nCreateTime);
|
||||||
NotifyWatchonlyChanged(true);
|
NotifyWatchonlyChanged(true);
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
return true;
|
return true;
|
||||||
return CWalletDB(strWalletFile).WriteWatchOnly(dest);
|
return CWalletDB(strWalletFile).WriteWatchOnly(dest, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
|
||||||
|
{
|
||||||
|
mapKeyMetadata[CScriptID(dest)].nCreateTime = nCreateTime;
|
||||||
|
return AddWatchOnly(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::RemoveWatchOnly(const CScript &dest)
|
bool CWallet::RemoveWatchOnly(const CScript &dest)
|
||||||
|
@ -1012,7 +1028,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
|
||||||
* TODO: One exception to this is that the abandoned state is cleared under the
|
* TODO: One exception to this is that the abandoned state is cleared under the
|
||||||
* assumption that any further notification of a transaction that was considered
|
* assumption that any further notification of a transaction that was considered
|
||||||
* abandoned is an indication that it is not safe to be considered abandoned.
|
* abandoned is an indication that it is not safe to be considered abandoned.
|
||||||
* Abandoned state should probably be more carefuly tracked via different
|
* Abandoned state should probably be more carefully tracked via different
|
||||||
* posInBlock signals or by checking mempool presence when necessary.
|
* posInBlock signals or by checking mempool presence when necessary.
|
||||||
*/
|
*/
|
||||||
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
|
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
|
||||||
|
@ -3416,14 +3432,16 @@ public:
|
||||||
void operator()(const CNoDestination &none) {}
|
void operator()(const CNoDestination &none) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
|
void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const {
|
||||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||||
mapKeyBirth.clear();
|
mapKeyBirth.clear();
|
||||||
|
|
||||||
// get birth times for keys with metadata
|
// get birth times for keys with metadata
|
||||||
for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
|
for (const auto& entry : mapKeyMetadata) {
|
||||||
if (it->second.nCreateTime)
|
if (entry.second.nCreateTime) {
|
||||||
mapKeyBirth[it->first] = it->second.nCreateTime;
|
mapKeyBirth[entry.first] = entry.second.nCreateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// map in which we'll infer heights of other keys
|
// map in which we'll infer heights of other keys
|
||||||
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
|
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
|
||||||
|
@ -3874,11 +3892,7 @@ bool CWallet::BackupWallet(const std::string& strDest)
|
||||||
pathDest /= strWalletFile;
|
pathDest /= strWalletFile;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
#if BOOST_VERSION >= 104000
|
|
||||||
boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
|
boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
|
||||||
#else
|
|
||||||
boost::filesystem::copy_file(pathSrc, pathDest);
|
|
||||||
#endif
|
|
||||||
LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
|
LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
|
||||||
return true;
|
return true;
|
||||||
} catch (const boost::filesystem::filesystem_error& e) {
|
} catch (const boost::filesystem::filesystem_error& e) {
|
||||||
|
|
|
@ -611,6 +611,20 @@ private:
|
||||||
bool fFileBacked;
|
bool fFileBacked;
|
||||||
|
|
||||||
std::set<int64_t> setKeyPool;
|
std::set<int64_t> setKeyPool;
|
||||||
|
|
||||||
|
int64_t nTimeFirstKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private version of AddWatchOnly method which does not accept a
|
||||||
|
* timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if
|
||||||
|
* the watch key did not previously have a timestamp associated with it.
|
||||||
|
* Because this is an inherited virtual method, it is accessible despite
|
||||||
|
* being marked private, but it is marked private anyway to encourage use
|
||||||
|
* of the other AddWatchOnly which accepts a timestamp and sets
|
||||||
|
* nTimeFirstKey more intelligently for more efficient rescans.
|
||||||
|
*/
|
||||||
|
bool AddWatchOnly(const CScript& dest) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
* Main wallet lock.
|
* Main wallet lock.
|
||||||
|
@ -635,7 +649,9 @@ public:
|
||||||
mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
|
mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
// Map from Key ID (for regular keys) or Script ID (for watch-only keys) to
|
||||||
|
// key metadata.
|
||||||
|
std::map<CTxDestination, CKeyMetadata> mapKeyMetadata;
|
||||||
|
|
||||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
|
@ -688,8 +704,6 @@ public:
|
||||||
|
|
||||||
std::set<COutPoint> setLockedCoins;
|
std::set<COutPoint> setLockedCoins;
|
||||||
|
|
||||||
int64_t nTimeFirstKey;
|
|
||||||
|
|
||||||
const CWalletTx* GetWalletTx(const uint256& hash) const;
|
const CWalletTx* GetWalletTx(const uint256& hash) const;
|
||||||
|
|
||||||
//! check whether we are allowed to upgrade (or already support) to the named feature
|
//! check whether we are allowed to upgrade (or already support) to the named feature
|
||||||
|
@ -723,19 +737,20 @@ public:
|
||||||
CPubKey GenerateNewKey();
|
CPubKey GenerateNewKey();
|
||||||
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret);
|
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret);
|
||||||
//! Adds a key to the store, and saves it to disk.
|
//! Adds a key to the store, and saves it to disk.
|
||||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
|
||||||
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
|
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
|
||||||
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
|
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
|
||||||
//! Load metadata (used by LoadWallet)
|
//! Load metadata (used by LoadWallet)
|
||||||
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
|
bool LoadKeyMetadata(const CTxDestination& pubKey, const CKeyMetadata &metadata);
|
||||||
|
|
||||||
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
||||||
|
void UpdateTimeFirstKey(int64_t nCreateTime);
|
||||||
|
|
||||||
//! Adds an encrypted key to the store, and saves it to disk.
|
//! Adds an encrypted key to the store, and saves it to disk.
|
||||||
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override;
|
||||||
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
|
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
|
||||||
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||||
bool AddCScript(const CScript& redeemScript);
|
bool AddCScript(const CScript& redeemScript) override;
|
||||||
bool LoadCScript(const CScript& redeemScript);
|
bool LoadCScript(const CScript& redeemScript);
|
||||||
|
|
||||||
//! Adds a destination data tuple to the store, and saves it to disk
|
//! Adds a destination data tuple to the store, and saves it to disk
|
||||||
|
@ -748,8 +763,8 @@ public:
|
||||||
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
|
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
|
||||||
|
|
||||||
//! Adds a watch-only address to the store, and saves it to disk.
|
//! Adds a watch-only address to the store, and saves it to disk.
|
||||||
bool AddWatchOnly(const CScript &dest);
|
bool AddWatchOnly(const CScript& dest, int64_t nCreateTime);
|
||||||
bool RemoveWatchOnly(const CScript &dest);
|
bool RemoveWatchOnly(const CScript &dest) override;
|
||||||
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
|
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
|
||||||
bool LoadWatchOnly(const CScript &dest);
|
bool LoadWatchOnly(const CScript &dest);
|
||||||
|
|
||||||
|
@ -757,7 +772,7 @@ public:
|
||||||
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
|
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
|
||||||
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
||||||
|
|
||||||
void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;
|
void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the next transaction order id
|
* Increment the next transaction order id
|
||||||
|
@ -771,11 +786,11 @@ public:
|
||||||
void MarkDirty();
|
void MarkDirty();
|
||||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
||||||
bool LoadToWallet(const CWalletTx& wtxIn);
|
bool LoadToWallet(const CWalletTx& wtxIn);
|
||||||
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock);
|
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock) override;
|
||||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
|
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
|
||||||
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
||||||
void ReacceptWalletTransactions();
|
void ReacceptWalletTransactions();
|
||||||
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman);
|
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
|
||||||
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
|
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
|
||||||
CAmount GetBalance() const;
|
CAmount GetBalance() const;
|
||||||
CAmount GetUnconfirmedBalance() const;
|
CAmount GetUnconfirmedBalance() const;
|
||||||
|
@ -857,7 +872,7 @@ public:
|
||||||
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
|
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
|
||||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||||
CAmount GetChange(const CTransaction& tx) const;
|
CAmount GetChange(const CTransaction& tx) const;
|
||||||
void SetBestChain(const CBlockLocator& loc);
|
void SetBestChain(const CBlockLocator& loc) override;
|
||||||
|
|
||||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||||
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
||||||
|
@ -867,9 +882,9 @@ public:
|
||||||
|
|
||||||
bool DelAddressBook(const CTxDestination& address);
|
bool DelAddressBook(const CTxDestination& address);
|
||||||
|
|
||||||
void UpdatedTransaction(const uint256 &hashTx);
|
void UpdatedTransaction(const uint256 &hashTx) override;
|
||||||
|
|
||||||
void Inventory(const uint256 &hash)
|
void Inventory(const uint256 &hash) override
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
@ -879,8 +894,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
|
void GetScriptForMining(boost::shared_ptr<CReserveScript> &script) override;
|
||||||
void ResetRequestCount(const uint256 &hash)
|
void ResetRequestCount(const uint256 &hash) override
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
mapRequestCount[hash] = 0;
|
mapRequestCount[hash] = 0;
|
||||||
|
|
|
@ -120,15 +120,19 @@ bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
|
||||||
return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
|
return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteWatchOnly(const CScript &dest)
|
bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
|
if (!Write(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta))
|
||||||
|
return false;
|
||||||
return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
|
return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::EraseWatchOnly(const CScript &dest)
|
bool CWalletDB::EraseWatchOnly(const CScript &dest)
|
||||||
{
|
{
|
||||||
nWalletDBUpdateCounter++;
|
nWalletDBUpdateCounter++;
|
||||||
|
if (!Erase(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest))))
|
||||||
|
return false;
|
||||||
return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
|
return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +263,7 @@ class CWalletScanState {
|
||||||
public:
|
public:
|
||||||
unsigned int nKeys;
|
unsigned int nKeys;
|
||||||
unsigned int nCKeys;
|
unsigned int nCKeys;
|
||||||
|
unsigned int nWatchKeys;
|
||||||
unsigned int nKeyMeta;
|
unsigned int nKeyMeta;
|
||||||
bool fIsEncrypted;
|
bool fIsEncrypted;
|
||||||
bool fAnyUnordered;
|
bool fAnyUnordered;
|
||||||
|
@ -266,7 +271,7 @@ public:
|
||||||
vector<uint256> vWalletUpgrade;
|
vector<uint256> vWalletUpgrade;
|
||||||
|
|
||||||
CWalletScanState() {
|
CWalletScanState() {
|
||||||
nKeys = nCKeys = nKeyMeta = 0;
|
nKeys = nCKeys = nWatchKeys = nKeyMeta = 0;
|
||||||
fIsEncrypted = false;
|
fIsEncrypted = false;
|
||||||
fAnyUnordered = false;
|
fAnyUnordered = false;
|
||||||
nFileVersion = 0;
|
nFileVersion = 0;
|
||||||
|
@ -348,16 +353,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
}
|
}
|
||||||
else if (strType == "watchs")
|
else if (strType == "watchs")
|
||||||
{
|
{
|
||||||
|
wss.nWatchKeys++;
|
||||||
CScript script;
|
CScript script;
|
||||||
ssKey >> *(CScriptBase*)(&script);
|
ssKey >> *(CScriptBase*)(&script);
|
||||||
char fYes;
|
char fYes;
|
||||||
ssValue >> fYes;
|
ssValue >> fYes;
|
||||||
if (fYes == '1')
|
if (fYes == '1')
|
||||||
pwallet->LoadWatchOnly(script);
|
pwallet->LoadWatchOnly(script);
|
||||||
|
|
||||||
// Watch-only addresses have no birthday information for now,
|
|
||||||
// so set the wallet birthday to the beginning of time.
|
|
||||||
pwallet->nTimeFirstKey = 1;
|
|
||||||
}
|
}
|
||||||
else if (strType == "key" || strType == "wkey")
|
else if (strType == "key" || strType == "wkey")
|
||||||
{
|
{
|
||||||
|
@ -458,20 +460,27 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
}
|
}
|
||||||
wss.fIsEncrypted = true;
|
wss.fIsEncrypted = true;
|
||||||
}
|
}
|
||||||
else if (strType == "keymeta")
|
else if (strType == "keymeta" || strType == "watchmeta")
|
||||||
|
{
|
||||||
|
CTxDestination keyID;
|
||||||
|
if (strType == "keymeta")
|
||||||
{
|
{
|
||||||
CPubKey vchPubKey;
|
CPubKey vchPubKey;
|
||||||
ssKey >> vchPubKey;
|
ssKey >> vchPubKey;
|
||||||
|
keyID = vchPubKey.GetID();
|
||||||
|
}
|
||||||
|
else if (strType == "watchmeta")
|
||||||
|
{
|
||||||
|
CScript script;
|
||||||
|
ssKey >> *(CScriptBase*)(&script);
|
||||||
|
keyID = CScriptID(script);
|
||||||
|
}
|
||||||
|
|
||||||
CKeyMetadata keyMeta;
|
CKeyMetadata keyMeta;
|
||||||
ssValue >> keyMeta;
|
ssValue >> keyMeta;
|
||||||
wss.nKeyMeta++;
|
wss.nKeyMeta++;
|
||||||
|
|
||||||
pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
|
pwallet->LoadKeyMetadata(keyID, keyMeta);
|
||||||
|
|
||||||
// find earliest key creation time, as wallet birthday
|
|
||||||
if (!pwallet->nTimeFirstKey ||
|
|
||||||
(keyMeta.nCreateTime < pwallet->nTimeFirstKey))
|
|
||||||
pwallet->nTimeFirstKey = keyMeta.nCreateTime;
|
|
||||||
}
|
}
|
||||||
else if (strType == "defaultkey")
|
else if (strType == "defaultkey")
|
||||||
{
|
{
|
||||||
|
@ -550,8 +559,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||||
bool fNoncriticalErrors = false;
|
bool fNoncriticalErrors = false;
|
||||||
DBErrors result = DB_LOAD_OK;
|
DBErrors result = DB_LOAD_OK;
|
||||||
|
|
||||||
try {
|
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
|
try {
|
||||||
int nMinVersion = 0;
|
int nMinVersion = 0;
|
||||||
if (Read((string)"minversion", nMinVersion))
|
if (Read((string)"minversion", nMinVersion))
|
||||||
{
|
{
|
||||||
|
@ -625,8 +634,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||||
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
|
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
|
||||||
|
|
||||||
// nTimeFirstKey is only reliable if all keys have metadata
|
// nTimeFirstKey is only reliable if all keys have metadata
|
||||||
if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
|
if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
|
||||||
pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
pwallet->UpdateTimeFirstKey(1);
|
||||||
|
|
||||||
BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
|
BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
|
||||||
WriteTx(pwallet->mapWallet[hash]);
|
WriteTx(pwallet->mapWallet[hash]);
|
||||||
|
|
|
@ -135,7 +135,7 @@ public:
|
||||||
|
|
||||||
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
|
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
|
||||||
|
|
||||||
bool WriteWatchOnly(const CScript &script);
|
bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);
|
||||||
bool EraseWatchOnly(const CScript &script);
|
bool EraseWatchOnly(const CScript &script);
|
||||||
|
|
||||||
bool WriteBestBlock(const CBlockLocator& locator);
|
bool WriteBestBlock(const CBlockLocator& locator);
|
||||||
|
|
Loading…
Reference in a new issue