aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am6
-rw-r--r--configure.ac2
-rw-r--r--contrib/README.md3
-rwxr-xr-xcontrib/devtools/github-merge.py20
-rwxr-xr-xcontrib/devtools/security-check.py34
-rwxr-xr-xcontrib/devtools/symbol-check.py63
-rwxr-xr-xcontrib/macdeploy/custom_dsstore.py6
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus136
-rw-r--r--contrib/rpm/README.md185
-rw-r--r--contrib/rpm/bitcoin-0.12.0-libressl.patch24
-rw-r--r--contrib/rpm/bitcoin.fc8
-rw-r--r--contrib/rpm/bitcoin.if157
-rw-r--r--contrib/rpm/bitcoin.spec444
-rw-r--r--contrib/rpm/bitcoin.te81
-rwxr-xr-xdepends/config.guess90
-rwxr-xr-xdepends/config.sub12
-rw-r--r--depends/packages/miniupnpc.mk4
-rw-r--r--doc/bips.md3
-rw-r--r--doc/release-notes.md11
-rwxr-xr-xqa/pull-tester/rpc-tests.py4
-rwxr-xr-xqa/rpc-tests/abandonconflict.py6
-rwxr-xr-xqa/rpc-tests/blockchain.py2
-rwxr-xr-xqa/rpc-tests/disablewallet.py14
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py34
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py10
-rwxr-xr-xqa/rpc-tests/httpbasics.py26
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py140
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py1
-rwxr-xr-xqa/rpc-tests/mempool_limit.py1
-rwxr-xr-xqa/rpc-tests/mempool_packages.py1
-rwxr-xr-xqa/rpc-tests/p2p-feefilter.py99
-rw-r--r--qa/rpc-tests/test_framework/authproxy.py7
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py14
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py61
-rw-r--r--qa/rpc-tests/test_framework/util.py60
-rwxr-xr-xqa/rpc-tests/wallet.py41
-rwxr-xr-xqa/rpc-tests/zapwallettxes.py10
-rwxr-xr-xshare/qt/extract_strings_qt.py9
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.test.include5
-rw-r--r--src/alert.cpp266
-rw-r--r--src/alert.h113
-rw-r--r--src/amount.cpp6
-rw-r--r--src/amount.h12
-rw-r--r--src/base58.cpp11
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/chainparams.h3
-rw-r--r--src/coincontrol.h5
-rw-r--r--src/init.cpp8
-rw-r--r--src/main.cpp166
-rw-r--r--src/main.h12
-rw-r--r--src/merkleblock.cpp14
-rw-r--r--src/merkleblock.h9
-rw-r--r--src/net.cpp20
-rw-r--r--src/net.h10
-rw-r--r--src/policy/fees.cpp19
-rw-r--r--src/policy/fees.h13
-rw-r--r--src/primitives/transaction.h3
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h14
-rw-r--r--src/qt/clientmodel.cpp37
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/coincontroldialog.cpp2
-rw-r--r--src/qt/forms/debugwindow.ui7
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/transactiondesc.cpp3
-rw-r--r--src/qt/transactionrecord.cpp7
-rw-r--r--src/qt/transactionrecord.h4
-rw-r--r--src/rpc/client.cpp3
-rw-r--r--src/rpc/mining.cpp109
-rw-r--r--src/rpc/rawtransaction.cpp8
-rw-r--r--src/rpc/server.cpp1
-rw-r--r--src/rpc/server.h1
-rw-r--r--src/test/alert_tests.cpp181
-rw-r--r--src/test/amount_tests.cpp42
-rw-r--r--src/test/bctest.py2
-rwxr-xr-xsrc/test/bitcoin-util-test.py2
-rw-r--r--src/test/bloom_tests.cpp23
-rw-r--r--src/test/data/alertTests.rawbin1279 -> 0 bytes
-rw-r--r--src/test/pmt_tests.cpp8
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/timedata.cpp2
-rw-r--r--src/timedata.h2
-rw-r--r--src/txmempool.cpp10
-rw-r--r--src/txmempool.h1
-rw-r--r--src/ui_interface.h5
-rw-r--r--src/uint256.h8
-rw-r--r--src/version.h5
-rw-r--r--src/wallet/rpcdump.cpp107
-rw-r--r--src/wallet/rpcwallet.cpp11
-rw-r--r--src/wallet/wallet.cpp63
-rw-r--r--src/wallet/wallet.h3
-rw-r--r--src/wallet/walletdb.cpp39
-rw-r--r--src/wallet/walletdb.h1
95 files changed, 2153 insertions, 1102 deletions
diff --git a/Makefile.am b/Makefile.am
index d6cbd7cb12..0929a59ed2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -110,7 +110,7 @@ osx_volname:
if BUILD_DARWIN
$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING)
- $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME)
+ $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME)
deploydir: $(OSX_DMG)
else
@@ -134,10 +134,10 @@ $(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE_DPIF
$(TIFFCP) -c none $(OSX_BACKGROUND_IMAGE_DPIFILES) $@
$(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN)
- $< "$@" "$(OSX_VOLNAME)"
+ $(PYTHON) $< "$@" "$(OSX_VOLNAME)"
$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING)
- INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2
+ INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2
deploydir: $(APP_DIST_EXTRAS)
endif
diff --git a/configure.ac b/configure.ac
index 939dfeaabf..8596307f38 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,7 +60,7 @@ AC_PATH_TOOL(STRIP, strip)
AC_PATH_TOOL(GCOV, gcov)
AC_PATH_PROG(LCOV, lcov)
AC_PATH_PROG(JAVA, java)
-AC_PATH_PROG(PYTHON, python)
+AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python])
AC_PATH_PROG(GENHTML, genhtml)
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
diff --git a/contrib/README.md b/contrib/README.md
index 5155ff0cb4..9461539166 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -42,6 +42,9 @@ Various PGP files of core developers.
### [MacDeploy](/contrib/macdeploy) ###
Scripts and notes for Mac builds.
+### [RPM](/contrib/rpm) ###
+RPM spec file for building bitcoin-core on RPM based distributions
+
Test and Verify Tools
---------------------
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index c8dcaae268..9a62fccbbb 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
# Copyright (c) 2016 Bitcoin Core Developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,6 +19,11 @@ import os,sys
from sys import stdin,stdout,stderr
import argparse
import subprocess
+import json,codecs
+try:
+ from urllib.request import Request,urlopen
+except:
+ from urllib2 import Request,urlopen
# External tools (can be overridden using environment)
GIT = os.getenv('GIT','git')
@@ -38,7 +43,7 @@ def git_config_get(option, default=None):
Get named configuration option from git repository.
'''
try:
- return subprocess.check_output([GIT,'config','--get',option]).rstrip()
+ return subprocess.check_output([GIT,'config','--get',option]).rstrip().decode('utf-8')
except subprocess.CalledProcessError as e:
return default
@@ -47,18 +52,19 @@ def retrieve_pr_title(repo,pull):
Retrieve pull request title from github.
Return None if no title can be found, or an error happens.
'''
- import urllib2,json
try:
- req = urllib2.Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
- result = urllib2.urlopen(req)
- result = json.load(result)
- return result['title']
+ req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
+ result = urlopen(req)
+ reader = codecs.getreader('utf-8')
+ obj = json.load(reader(result))
+ return obj['title']
except Exception as e:
print('Warning: unable to retrieve pull title from github: %s' % e)
return None
def ask_prompt(text):
print(text,end=" ",file=stderr)
+ stderr.flush()
reply = stdin.readline().rstrip()
print("",file=stderr)
return reply
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 0319f739c4..301fea85c1 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -5,7 +5,7 @@ Exit status will be 0 if successful, and the program will be silent.
Otherwise the exit status will be 1 and it will log which executables failed which checks.
Needs `readelf` (for ELF) and `objdump` (for PE).
'''
-from __future__ import division,print_function
+from __future__ import division,print_function,unicode_literals
import subprocess
import sys
import os
@@ -23,9 +23,9 @@ def check_ELF_PIE(executable):
raise IOError('Error opening file')
ok = False
- for line in stdout.split('\n'):
+ for line in stdout.split(b'\n'):
line = line.split()
- if len(line)>=2 and line[0] == 'Type:' and line[1] == 'DYN':
+ if len(line)>=2 and line[0] == b'Type:' and line[1] == b'DYN':
ok = True
return ok
@@ -38,17 +38,17 @@ def get_ELF_program_headers(executable):
in_headers = False
count = 0
headers = []
- for line in stdout.split('\n'):
- if line.startswith('Program Headers:'):
+ for line in stdout.split(b'\n'):
+ if line.startswith(b'Program Headers:'):
in_headers = True
- if line == '':
+ if line == b'':
in_headers = False
if in_headers:
if count == 1: # header line
- ofs_typ = line.find('Type')
- ofs_offset = line.find('Offset')
- ofs_flags = line.find('Flg')
- ofs_align = line.find('Align')
+ ofs_typ = line.find(b'Type')
+ ofs_offset = line.find(b'Offset')
+ ofs_flags = line.find(b'Flg')
+ ofs_align = line.find(b'Align')
if ofs_typ == -1 or ofs_offset == -1 or ofs_flags == -1 or ofs_align == -1:
raise ValueError('Cannot parse elfread -lW output')
elif count > 1:
@@ -65,9 +65,9 @@ def check_ELF_NX(executable):
have_wx = False
have_gnu_stack = False
for (typ, flags) in get_ELF_program_headers(executable):
- if typ == 'GNU_STACK':
+ if typ == b'GNU_STACK':
have_gnu_stack = True
- if 'W' in flags and 'E' in flags: # section is both writable and executable
+ if b'W' in flags and b'E' in flags: # section is both writable and executable
have_wx = True
return have_gnu_stack and not have_wx
@@ -84,7 +84,7 @@ def check_ELF_RELRO(executable):
# However, the dynamic linker need to write to this area so these are RW.
# Glibc itself takes care of mprotecting this area R after relocations are finished.
# See also http://permalink.gmane.org/gmane.comp.gnu.binutils/71347
- if typ == 'GNU_RELRO':
+ if typ == b'GNU_RELRO':
have_gnu_relro = True
have_bindnow = False
@@ -92,9 +92,9 @@ def check_ELF_RELRO(executable):
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
- for line in stdout.split('\n'):
+ for line in stdout.split(b'\n'):
tokens = line.split()
- if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2]):
+ if len(tokens)>1 and tokens[1] == b'(BIND_NOW)' or (len(tokens)>2 and tokens[1] == b'(FLAGS)' and b'BIND_NOW' in tokens[2]):
have_bindnow = True
return have_gnu_relro and have_bindnow
@@ -107,8 +107,8 @@ def check_ELF_Canary(executable):
if p.returncode:
raise IOError('Error opening file')
ok = False
- for line in stdout.split('\n'):
- if '__stack_chk_fail' in line:
+ for line in stdout.split(b'\n'):
+ if b'__stack_chk_fail' in line:
ok = True
return ok
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 4ad5136f79..e26c0fbb94 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -11,7 +11,7 @@ Example usage:
find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
'''
-from __future__ import division, print_function
+from __future__ import division, print_function, unicode_literals
import subprocess
import re
import sys
@@ -47,28 +47,28 @@ MAX_VERSIONS = {
# Ignore symbols that are exported as part of every executable
IGNORE_EXPORTS = {
-'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used'
+b'_edata', b'_end', b'_init', b'__bss_start', b'_fini', b'_IO_stdin_used'
}
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
# Allowed NEEDED libraries
ALLOWED_LIBRARIES = {
# bitcoind and bitcoin-qt
-'libgcc_s.so.1', # GCC base support
-'libc.so.6', # C library
-'libpthread.so.0', # threading
-'libanl.so.1', # DNS resolve
-'libm.so.6', # math library
-'librt.so.1', # real-time (clock)
-'ld-linux-x86-64.so.2', # 64-bit dynamic linker
-'ld-linux.so.2', # 32-bit dynamic linker
+b'libgcc_s.so.1', # GCC base support
+b'libc.so.6', # C library
+b'libpthread.so.0', # threading
+b'libanl.so.1', # DNS resolve
+b'libm.so.6', # math library
+b'librt.so.1', # real-time (clock)
+b'ld-linux-x86-64.so.2', # 64-bit dynamic linker
+b'ld-linux.so.2', # 32-bit dynamic linker
# bitcoin-qt only
-'libX11-xcb.so.1', # part of X11
-'libX11.so.6', # part of X11
-'libxcb.so.1', # part of X11
-'libfontconfig.so.1', # font support
-'libfreetype.so.6', # font parsing
-'libdl.so.2' # programming interface to dynamic linker
+b'libX11-xcb.so.1', # part of X11
+b'libX11.so.6', # part of X11
+b'libxcb.so.1', # part of X11
+b'libfontconfig.so.1', # font support
+b'libfreetype.so.6', # font parsing
+b'libdl.so.2' # programming interface to dynamic linker
}
class CPPFilt(object):
@@ -81,7 +81,8 @@ class CPPFilt(object):
self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
def __call__(self, mangled):
- self.proc.stdin.write(mangled + '\n')
+ self.proc.stdin.write(mangled + b'\n')
+ self.proc.stdin.flush()
return self.proc.stdout.readline().rstrip()
def close(self):
@@ -99,24 +100,24 @@ def read_symbols(executable, imports=True):
if p.returncode:
raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip()))
syms = []
- for line in stdout.split('\n'):
+ for line in stdout.split(b'\n'):
line = line.split()
- if len(line)>7 and re.match('[0-9]+:$', line[0]):
- (sym, _, version) = line[7].partition('@')
- is_import = line[6] == 'UND'
- if version.startswith('@'):
+ if len(line)>7 and re.match(b'[0-9]+:$', line[0]):
+ (sym, _, version) = line[7].partition(b'@')
+ is_import = line[6] == b'UND'
+ if version.startswith(b'@'):
version = version[1:]
if is_import == imports:
syms.append((sym, version))
return syms
def check_version(max_versions, version):
- if '_' in version:
- (lib, _, ver) = version.rpartition('_')
+ if b'_' in version:
+ (lib, _, ver) = version.rpartition(b'_')
else:
lib = version
ver = '0'
- ver = tuple([int(x) for x in ver.split('.')])
+ ver = tuple([int(x) for x in ver.split(b'.')])
if not lib in max_versions:
return False
return ver <= max_versions[lib]
@@ -127,10 +128,10 @@ def read_libraries(filename):
if p.returncode:
raise IOError('Error opening file')
libraries = []
- for line in stdout.split('\n'):
+ for line in stdout.split(b'\n'):
tokens = line.split()
- if len(tokens)>2 and tokens[1] == '(NEEDED)':
- match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
+ if len(tokens)>2 and tokens[1] == b'(NEEDED)':
+ match = re.match(b'^Shared library: \[(.*)\]$', b' '.join(tokens[2:]))
if match:
libraries.append(match.group(1))
else:
@@ -144,18 +145,18 @@ if __name__ == '__main__':
# Check imported symbols
for sym,version in read_symbols(filename, True):
if version and not check_version(MAX_VERSIONS, version):
- print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version))
+ print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym).decode('utf-8'), version.decode('utf-8')))
retval = 1
# Check exported symbols
for sym,version in read_symbols(filename, False):
if sym in IGNORE_EXPORTS:
continue
- print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))
+ print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym).decode('utf-8')))
retval = 1
# Check dependency libraries
for library_name in read_libraries(filename):
if library_name not in ALLOWED_LIBRARIES:
- print('%s: NEEDED library %s is not allowed' % (filename, library_name))
+ print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8')))
retval = 1
exit(retval)
diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py
index 8481e903a0..03e2325fc0 100755
--- a/contrib/macdeploy/custom_dsstore.py
+++ b/contrib/macdeploy/custom_dsstore.py
@@ -2,7 +2,7 @@
# Copyright (c) 2013-2015 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 __future__ import division,print_function,unicode_literals
import biplist
from ds_store import DSStore
from mac_alias import Alias
@@ -14,7 +14,7 @@ package_name_ns = sys.argv[2]
ds = DSStore.open(output_file, 'w+')
ds['.']['bwsp'] = {
'ShowStatusBar': False,
- 'WindowBounds': '{{300, 280}, {500, 343}}',
+ 'WindowBounds': b'{{300, 280}, {500, 343}}',
'ContainerShowSidebar': False,
'SidebarWidth': 0,
'ShowTabView': False,
@@ -28,7 +28,7 @@ icvp = {
'gridOffsetX': 0.0,
'textSize': 12.0,
'viewOptionsVersion': 1,
- 'backgroundImageAlias': '\x00\x00\x00\x00\x02\x1e\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x06\x00\x00\x00\x00\x01\x06\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07bitcoin\x00\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00',
+ 'backgroundImageAlias': b'\x00\x00\x00\x00\x02\x1e\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x06\x00\x00\x00\x00\x01\x06\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07bitcoin\x00\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00',
'backgroundColorBlue': 1.0,
'iconSize': 96.0,
'backgroundColorGreen': 1.0,
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 7e6270c743..685ed8e5b8 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-
+from __future__ import division, print_function, unicode_literals
#
# Copyright (C) 2011 Patrick "p2k" Schneider <me@p2k-network.org>
#
@@ -201,7 +201,7 @@ class DeploymentInfo(object):
def getFrameworks(binaryPath, verbose):
if verbose >= 3:
- print "Inspecting with otool: " + binaryPath
+ print("Inspecting with otool: " + binaryPath)
otoolbin=os.getenv("OTOOL", "otool")
otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
o_stdout, o_stderr = otool.communicate()
@@ -222,8 +222,8 @@ def getFrameworks(binaryPath, verbose):
info = FrameworkInfo.fromOtoolLibraryLine(line.strip())
if info is not None:
if verbose >= 3:
- print "Found framework:"
- print info
+ print("Found framework:")
+ print(info)
libraries.append(info)
return libraries
@@ -234,24 +234,24 @@ def runInstallNameTool(action, *args):
def changeInstallName(oldName, newName, binaryPath, verbose):
if verbose >= 3:
- print "Using install_name_tool:"
- print " in", binaryPath
- print " change reference", oldName
- print " to", newName
+ print("Using install_name_tool:")
+ print(" in", binaryPath)
+ print(" change reference", oldName)
+ print(" to", newName)
runInstallNameTool("change", oldName, newName, binaryPath)
def changeIdentification(id, binaryPath, verbose):
if verbose >= 3:
- print "Using install_name_tool:"
- print " change identification in", binaryPath
- print " to", id
+ print("Using install_name_tool:")
+ print(" change identification in", binaryPath)
+ print(" to", id)
runInstallNameTool("id", id, binaryPath)
def runStrip(binaryPath, verbose):
stripbin=os.getenv("STRIP", "strip")
if verbose >= 3:
- print "Using strip:"
- print " stripped", binaryPath
+ print("Using strip:")
+ print(" stripped", binaryPath)
subprocess.check_call([stripbin, "-x", binaryPath])
def copyFramework(framework, path, verbose):
@@ -274,8 +274,8 @@ def copyFramework(framework, path, verbose):
shutil.copy2(fromPath, toPath)
if verbose >= 3:
- print "Copied:", fromPath
- print " to:", toPath
+ print("Copied:", fromPath)
+ print(" to:", toPath)
permissions = os.stat(toPath)
if not permissions.st_mode & stat.S_IWRITE:
@@ -288,14 +288,14 @@ def copyFramework(framework, path, verbose):
if not os.path.exists(linkfrom):
os.symlink(linkto, linkfrom)
if verbose >= 2:
- print "Linked:", linkfrom, "->", linkto
+ print("Linked:", linkfrom, "->", linkto)
fromResourcesDir = framework.sourceResourcesDirectory
if os.path.exists(fromResourcesDir):
toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory)
shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True)
if verbose >= 3:
- print "Copied resources:", fromResourcesDir
- print " to:", toResourcesDir
+ print("Copied resources:", fromResourcesDir)
+ print(" to:", toResourcesDir)
fromContentsDir = framework.sourceVersionContentsDirectory
if not os.path.exists(fromContentsDir):
fromContentsDir = framework.sourceContentsDirectory
@@ -304,16 +304,16 @@ def copyFramework(framework, path, verbose):
shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory)
if verbose >= 3:
- print "Copied Contents:", fromContentsDir
- print " to:", toContentsDir
+ print("Copied Contents:", fromContentsDir)
+ print(" to:", toContentsDir)
elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout)
qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib")
qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib")
if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath):
shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True)
if verbose >= 3:
- print "Copied for libQtGui:", qtMenuNibSourcePath
- print " to:", qtMenuNibDestinationPath
+ print("Copied for libQtGui:", qtMenuNibSourcePath)
+ print(" to:", qtMenuNibDestinationPath)
return toPath
@@ -326,7 +326,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym
deploymentInfo.deployedFrameworks.append(framework.frameworkName)
if verbose >= 2:
- print "Processing", framework.frameworkName, "..."
+ print("Processing", framework.frameworkName, "...")
# Get the Qt path from one of the Qt frameworks
if deploymentInfo.qtPath is None and framework.isQtFramework():
@@ -334,7 +334,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym
if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath):
if verbose >= 2:
- print framework.frameworkName, "already deployed, skipping."
+ print(framework.frameworkName, "already deployed, skipping.")
continue
# install_name_tool the new id into the binary
@@ -366,7 +366,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym
def deployFrameworksForAppBundle(applicationBundle, strip, verbose):
frameworks = getFrameworks(applicationBundle.binaryPath, verbose)
if len(frameworks) == 0 and verbose >= 1:
- print "Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path)
+ print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path))
return DeploymentInfo()
else:
return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose)
@@ -444,7 +444,7 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
for pluginDirectory, pluginName in plugins:
if verbose >= 2:
- print "Processing plugin", os.path.join(pluginDirectory, pluginName), "..."
+ print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...")
sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName)
destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory)
@@ -454,8 +454,8 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
destinationPath = os.path.join(destinationDirectory, pluginName)
shutil.copy2(sourcePath, destinationPath)
if verbose >= 3:
- print "Copied:", sourcePath
- print " to:", destinationPath
+ print("Copied:", sourcePath)
+ print(" to:", destinationPath)
if strip:
runStrip(destinationPath, verbose)
@@ -525,7 +525,7 @@ if config.translations_dir and config.translations_dir[0]:
for p in config.add_resources:
if verbose >= 3:
- print "Checking for \"%s\"..." % p
+ print("Checking for \"%s\"..." % p)
if not os.path.exists(p):
if verbose >= 1:
sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p))
@@ -535,7 +535,7 @@ for p in config.add_resources:
if len(config.fancy) == 1:
if verbose >= 3:
- print "Fancy: Importing plistlib..."
+ print("Fancy: Importing plistlib...")
try:
import plistlib
except ImportError:
@@ -545,7 +545,7 @@ if len(config.fancy) == 1:
p = config.fancy[0]
if verbose >= 3:
- print "Fancy: Loading \"%s\"..." % p
+ print("Fancy: Loading \"%s\"..." % p)
if not os.path.exists(p):
if verbose >= 1:
sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p))
@@ -559,23 +559,23 @@ if len(config.fancy) == 1:
sys.exit(1)
try:
- assert not fancy.has_key("window_bounds") or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4)
- assert not fancy.has_key("background_picture") or isinstance(fancy["background_picture"], str)
- assert not fancy.has_key("icon_size") or isinstance(fancy["icon_size"], int)
- assert not fancy.has_key("applications_symlink") or isinstance(fancy["applications_symlink"], bool)
- if fancy.has_key("items_position"):
+ assert "window_bounds" not in fancy or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4)
+ assert "background_picture" not in fancy or isinstance(fancy["background_picture"], str)
+ assert "icon_size" not in fancy or isinstance(fancy["icon_size"], int)
+ assert "applications_symlink" not in fancy or isinstance(fancy["applications_symlink"], bool)
+ if "items_position" in fancy:
assert isinstance(fancy["items_position"], dict)
- for key, value in fancy["items_position"].iteritems():
+ for key, value in fancy["items_position"].items():
assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int)
except:
if verbose >= 1:
sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p))
sys.exit(1)
- if fancy.has_key("background_picture"):
+ if "background_picture" in fancy:
bp = fancy["background_picture"]
if verbose >= 3:
- print "Fancy: Resolving background picture \"%s\"..." % bp
+ print("Fancy: Resolving background picture \"%s\"..." % bp)
if not os.path.exists(bp):
bp = os.path.join(os.path.dirname(p), bp)
if not os.path.exists(bp):
@@ -591,7 +591,7 @@ else:
if os.path.exists("dist"):
if verbose >= 2:
- print "+ Removing old dist folder +"
+ print("+ Removing old dist folder +")
shutil.rmtree("dist")
@@ -607,9 +607,9 @@ else:
target = os.path.join("dist", "Bitcoin-Qt.app")
if verbose >= 2:
- print "+ Copying source bundle +"
+ print("+ Copying source bundle +")
if verbose >= 3:
- print app_bundle, "->", target
+ print(app_bundle, "->", target)
os.mkdir("dist")
shutil.copytree(app_bundle, target, symlinks=True)
@@ -619,7 +619,7 @@ applicationBundle = ApplicationBundleInfo(target)
# ------------------------------------------------
if verbose >= 2:
- print "+ Deploying frameworks +"
+ print("+ Deploying frameworks +")
try:
deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose)
@@ -638,7 +638,7 @@ except RuntimeError as e:
if config.plugins:
if verbose >= 2:
- print "+ Deploying plugins +"
+ print("+ Deploying plugins +")
try:
deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose)
@@ -664,7 +664,7 @@ else:
for lng_file in add_qt_tr:
p = os.path.join(qt_tr_dir, lng_file)
if verbose >= 3:
- print "Checking for \"%s\"..." % p
+ print("Checking for \"%s\"..." % p)
if not os.path.exists(p):
if verbose >= 1:
sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file))
@@ -673,7 +673,7 @@ else:
# ------------------------------------------------
if verbose >= 2:
- print "+ Installing qt.conf +"
+ print("+ Installing qt.conf +")
f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb")
f.write(qt_conf)
@@ -682,22 +682,22 @@ f.close()
# ------------------------------------------------
if len(add_qt_tr) > 0 and verbose >= 2:
- print "+ Adding Qt translations +"
+ print("+ Adding Qt translations +")
for lng_file in add_qt_tr:
if verbose >= 3:
- print os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file)
+ print(os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file))
shutil.copy2(os.path.join(qt_tr_dir, lng_file), os.path.join(applicationBundle.resourcesPath, lng_file))
# ------------------------------------------------
if len(config.add_resources) > 0 and verbose >= 2:
- print "+ Adding additional resources +"
+ print("+ Adding additional resources +")
for p in config.add_resources:
t = os.path.join(applicationBundle.resourcesPath, os.path.basename(p))
if verbose >= 3:
- print p, "->", t
+ print(p, "->", t)
if os.path.isdir(p):
shutil.copytree(p, t, symlinks=True)
else:
@@ -706,10 +706,10 @@ for p in config.add_resources:
# ------------------------------------------------
if config.sign and 'CODESIGNARGS' not in os.environ:
- print "You must set the CODESIGNARGS environment variable. Skipping signing."
+ print("You must set the CODESIGNARGS environment variable. Skipping signing.")
elif config.sign:
if verbose >= 1:
- print "Code-signing app bundle %s"%(target,)
+ print("Code-signing app bundle %s"%(target,))
subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True)
# ------------------------------------------------
@@ -734,7 +734,7 @@ if config.dmg is not None:
def runHDIUtil(verb, image_basename, **kwargs):
hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"]
- if kwargs.has_key("capture_stdout"):
+ if "capture_stdout" in kwargs:
del kwargs["capture_stdout"]
run = subprocess.check_output
else:
@@ -744,7 +744,7 @@ if config.dmg is not None:
hdiutil_args.append("-verbose")
run = subprocess.check_call
- for key, value in kwargs.iteritems():
+ for key, value in kwargs.items():
hdiutil_args.append("-" + key)
if not value is True:
hdiutil_args.append(str(value))
@@ -753,9 +753,9 @@ if config.dmg is not None:
if verbose >= 2:
if fancy is None:
- print "+ Creating .dmg disk image +"
+ print("+ Creating .dmg disk image +")
else:
- print "+ Preparing .dmg disk image +"
+ print("+ Preparing .dmg disk image +")
if config.dmg != "":
dmg_name = config.dmg
@@ -770,7 +770,7 @@ if config.dmg is not None:
sys.exit(e.returncode)
else:
if verbose >= 3:
- print "Determining size of \"dist\"..."
+ print("Determining size of \"dist\"...")
size = 0
for path, dirs, files in os.walk("dist"):
for file in files:
@@ -778,14 +778,14 @@ if config.dmg is not None:
size += int(size * 0.15)
if verbose >= 3:
- print "Creating temp image for modification..."
+ print("Creating temp image for modification...")
try:
runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=volname, ov=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
if verbose >= 3:
- print "Attaching temp image..."
+ print("Attaching temp image...")
try:
output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True)
except subprocess.CalledProcessError as e:
@@ -796,13 +796,13 @@ if config.dmg is not None:
disk_name = m.group(1)
if verbose >= 2:
- print "+ Applying fancy settings +"
+ print("+ Applying fancy settings +")
- if fancy.has_key("background_picture"):
+ if "background_picture" in fancy:
bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"]))
os.mkdir(os.path.dirname(bg_path))
if verbose >= 3:
- print fancy["background_picture"], "->", bg_path
+ print(fancy["background_picture"], "->", bg_path)
shutil.copy2(fancy["background_picture"], bg_path)
else:
bg_path = None
@@ -839,8 +839,8 @@ if config.dmg is not None:
itemscript = Template('set position of item "${item}" of container window to {${position}}')
items_positions = []
- if fancy.has_key("items_position"):
- for name, position in fancy["items_position"].iteritems():
+ if "items_position" in fancy:
+ for name, position in fancy["items_position"].items():
params = { "item" : name, "position" : ",".join([str(p) for p in position]) }
items_positions.append(itemscript.substitute(params))
@@ -851,9 +851,9 @@ if config.dmg is not None:
"background_commands" : "",
"items_positions" : "\n ".join(items_positions)
}
- if fancy.has_key("window_bounds"):
+ if "window_bounds" in fancy:
params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]])
- if fancy.has_key("icon_size"):
+ if "icon_size" in fancy:
params["icon_size"] = str(fancy["icon_size"])
if bg_path is not None:
# Set background file, then call SetFile to make it invisible.
@@ -873,7 +873,7 @@ if config.dmg is not None:
print("Error running osascript.")
if verbose >= 2:
- print "+ Finalizing .dmg disk image +"
+ print("+ Finalizing .dmg disk image +")
time.sleep(5)
try:
@@ -886,6 +886,6 @@ if config.dmg is not None:
# ------------------------------------------------
if verbose >= 2:
- print "+ Done +"
+ print("+ Done +")
sys.exit(0)
diff --git a/contrib/rpm/README.md b/contrib/rpm/README.md
new file mode 100644
index 0000000000..aecb3ba84f
--- /dev/null
+++ b/contrib/rpm/README.md
@@ -0,0 +1,185 @@
+RPM Spec File Notes
+-------------------
+
+The RPM spec file provided here is for Bitcoin-Core 0.12.0 and builds on CentOS
+7 with either the CentOS provided OpenSSL library or with LibreSSL as packaged
+at [LibreLAMP.com](https://librelamp.com/). It should hopefully not be too
+difficult to port the RPM spec file to most RPM based Linux distributions.
+
+When porting the spec file to build for a particular distribution, there are
+some important notes.
+
+## Sources
+
+It is considered good form for all sources to reference a URL where the source
+can be downloaded.
+
+Sources 0-9 should be reserved for source code tarballs. `Source0` should
+reference the release tarball available from https://bitcoin.org/bin/ and
+`Source1` should reference the BerkeleyDB source.
+
+Sources 10-99 are for source files that are maintained in the
+[Bitcoin git repository](https://github.com/bitcoin/bitcoin) but are not part of
+the release tarball. Most of these will reside in the `contrib` sub-directory.
+
+Sources 10-19 should be reserved for miscellaneous configuration files.
+Currently only `Source10` is used, for the example `bitcoin.conf` file.
+
+Sources 20-29 should be reserved for man pages. Currently only `Source20`
+through `Source23` are used.
+
+Sources 30-39 should be reserved for SELinux related files. Currently only
+`Source30` through `Source32` are used. Until those files are in a tagged
+release, the full URL specified in the RPM spec file will not work. You can get
+them from the git ropository where you retrieved this file.
+
+Sources 100+ are for files that are not source tarballs and are not maintained
+in the bitcoin git repository. At present only an SVG version of the Bitcoin
+icon is used.
+
+## Patches
+
+In general, patches should be avoided. When a packager feels a patch is
+necessary, the packager should bring the problem to the attention of the bitcoin
+developers so that an official fix to the issue can make it into the next
+release.
+
+### Patch0 bitcoin-0.12.0-libressl.patch
+
+This patch is only needed if building against LibreSSL. LibreSSL is not the
+standard TLS library on most Linux distributions. The patch will likely not be
+needed when 0.12.1 is released, a proper fix is already in the Bitcoin git
+master branch.
+
+## BuildRequires
+
+The packages specified in the `BuildRequires` are specified according to the
+package naming convention currently used in CentOS 7 and EPEL for CentOS 7. You
+may need to change some of the package names for other distributions. This is
+most likely to be the case with the Qt packages.
+
+## BerkeleyDB
+
+The `build-unix.md` file recommends building against BerkeleyDB 4.8.30. Even if
+that is the version your Linux distribution ships with, it probably is a good
+idea to build Bitcoin Core against a static version of that library compiled
+according to the instructions in the `build-unix.md` file so that any changes
+the distribution may make in the future will not result in a problem for users.
+
+The problem that can exist, clients built against different versions of
+BerkeleyDB may not be able read each other's `wallet.dat` file which can make it
+difficult for a user to recover from backup in the event of a system failure.
+
+## Graphical User Interface and Qt Version
+
+The RPM spec file will by default build the GUI client linked against the Qt5
+libraries. If you wish instead to link against the Qt4 libraries you need to
+pass the switch `-D '_use_qt4 1'` at build time to the `rpmbuild` or `mock`
+command used to build the packages.
+
+If you would prefer not to build the GUI at all, you can pass the switch
+`-D '_no_gui 1'` to the `rpmbuild` or `mock` build command.
+
+## Desktop and KDE Files
+
+The desktop and KDE meta files are created in the spec file itself with the
+`cat` command. This is done to allow easy distribution specific changes without
+needing to use any patches. A specific time stamp is given to the files so that
+it does not they do not appear to have been updated every time the package is
+built. If you do make changes to them, you probably should update time stamp
+assigned to them in the `touch` command that specifies the time stamp.
+
+## SVG, PNG, and XPM Icons
+
+The `bitcoin.svg` file is from the source listed as `Source100`. It is used as
+the source for the PNG and XPM files. The generated PNG and XPM files are given
+the same time stamp as the source SVG file as a means of indicating they are
+derived from it.
+
+## Systemd
+
+This spec file assumes the target distribution uses systemd. That really only
+matters for the `bitcoin-server` package. At this point, most RPM based
+distributions that still receive vendor updates do in fact use systemd.
+
+The files to control the service are created in the RPM spec file itself using
+the `cat` command. This is done to make it easy to modify for other
+distributions that may implement things differently without needing to patch
+source. A specific time stamp is given to the files so that they do not appear
+to have been updated every time the package is built. If you do make changes to
+them, you probably should update the time stamp assigned to them in the `touch`
+command that specifies the time stamp.
+
+## SELinux
+
+The `bitcoin-server` package should have SELinux support. How to properly do
+that *may* vary by distribution and version of distribution.
+
+The SELinux stuff in this RPM spec file *should* be correct for CentOS, RHEL,
+and Fedora but it would be a good idea to review it before building the package
+on other distributions.
+
+## Tests
+
+The `%check` section takes a very long time to run. If your build system has a
+time limit for package build, you may need to make an exception for this
+package. On CentOS 7 the `%check` section completes successfully with both
+OpenSSL and LibreSSL, a failure really does mean something is wrong.
+
+## LibreSSL Build Notes
+
+To build against LibreSSL you will need to pass the switch
+`-D '_use_libressl 1'` to the `rpmbuild` or `mock` command or the spec file will
+want the OpenSSL development files.
+
+### LibreSSL and Boost
+
+LibreSSL (and some newer builds of OpenSSL) do not have support for SSLv3. This
+can cause issues with the Boost package if the Boost package has not been
+patched accordingly. On those distributions, you will either need to build
+Bitcoin-Core against OpenSSL or use a patched version of Boost in the build
+system.
+
+As SSLv3 is no longer safe, distributions that have not patched Boost to work
+with TLS libraries that do not support SSLv3 should have bug reports filed
+against the Boost package. This bug report has already been filed for RHEL 7 but
+it may need to be filed for other distributions.
+
+A patch for Boost: https://github.com/boostorg/asio/pull/23/files
+
+## ZeroMQ
+
+At this time, this RPM spec file does not support the ZeroMQ build options. A
+suitable version of ZeroMQ is not available for the platform this spec file was
+developed on (CentOS 7).
+
+## Legacy Credit
+
+This RPM spec file is largely based upon the work of Michael Hampton at
+[Ringing Liberty](https://www.ringingliberty.com/bitcoin/). He has been
+packaging Bitcoin for Fedora at least since 2012.
+
+Most of the differences between his packaging and this package are stylistic in
+nature. The major differences:
+
+1. He builds from a github tagged release rather than a release tarball. This
+should not result in different source code.
+
+2. He does not build BerkeleyDB but instead uses the BerkeleyDB provided by the
+Linux distribution. For the distributions he packages for, they currently all
+use the same version of BerkeleyDB so that difference is *probably* just
+academic.
+
+3. As of his 10.11.2 package he did not allow for building against LibreSSL,
+specifying a build without the Qt GUI, or specifying which version of the Qt
+libraries to use.
+
+4. I renamed the `bitcoin` package that contains the Qt GUI to `bitcoin-core` as
+that appears to be how the general population refers to it, in contrast to
+`bitcoin-xt` or `bitcoin-classic`. I wanted to make sure the general population
+knows what they are getting when installing the GUI package.
+
+As far as minor differences, I generally prefer to assign the file permissions
+in the `%files` portion of an RPM spec file rather than specifying the
+permissions of a file during `%install` and other minor things like that that
+are largely just cosmetic.
diff --git a/contrib/rpm/bitcoin-0.12.0-libressl.patch b/contrib/rpm/bitcoin-0.12.0-libressl.patch
new file mode 100644
index 0000000000..555614a06d
--- /dev/null
+++ b/contrib/rpm/bitcoin-0.12.0-libressl.patch
@@ -0,0 +1,24 @@
+diff -ur bitcoin-0.12.0.orig/src/init.cpp bitcoin-0.12.0/src/init.cpp
+--- bitcoin-0.12.0.orig/src/init.cpp 2015-12-31 16:00:00.000000000 -0800
++++ bitcoin-0.12.0/src/init.cpp 2016-02-23 06:03:47.133227757 -0800
+@@ -1075,7 +1075,7 @@
+ if (fPrintToDebugLog)
+ OpenDebugLog();
+
+-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
++#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
+ #else
+ LogPrintf("Using OpenSSL version %s\n", OpenSSL_version(OPENSSL_VERSION));
+diff -ur bitcoin-0.12.0.orig/src/qt/rpcconsole.cpp bitcoin-0.12.0/src/qt/rpcconsole.cpp
+--- bitcoin-0.12.0.orig/src/qt/rpcconsole.cpp 2015-12-31 16:00:00.000000000 -0800
++++ bitcoin-0.12.0/src/qt/rpcconsole.cpp 2016-02-23 15:09:42.881126841 -0800
+@@ -264,7 +264,7 @@
+
+ // set library version labels
+
+-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
++#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
+ #else
+ ui->openSSLVersion->setText(OpenSSL_version(OPENSSL_VERSION));
diff --git a/contrib/rpm/bitcoin.fc b/contrib/rpm/bitcoin.fc
new file mode 100644
index 0000000000..6f5eef6375
--- /dev/null
+++ b/contrib/rpm/bitcoin.fc
@@ -0,0 +1,8 @@
+/usr/bin/bitcoin-cli -- gen_context(system_u:object_r:bitcoin_exec_t,s0)
+/usr/sbin/bitcoind -- gen_context(system_u:object_r:bitcoin_exec_t,s0)
+/usr/lib(64)?/bitcoin/bitcoind -- gen_context(system_u:object_r:bitcoin_exec_t,s0)
+
+/etc/bitcoin(/.*)? gen_context(system_u:object_r:bitcoin_conf_t,s0)
+/var/lib/bitcoin(/.*)? gen_context(system_u:object_r:bitcoin_var_lib_t,s0)
+
+(/var)?/run/bitcoind(/.*)? gen_context(system_u:object_r:bitcoin_var_run_t,s0)
diff --git a/contrib/rpm/bitcoin.if b/contrib/rpm/bitcoin.if
new file mode 100644
index 0000000000..2b096c24dc
--- /dev/null
+++ b/contrib/rpm/bitcoin.if
@@ -0,0 +1,157 @@
+
+## <summary>policy for bitcoin</summary>
+
+
+########################################
+## <summary>
+## Transition to bitcoin.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed to transition.
+## </summary>
+## </param>
+#
+interface(`bitcoin_domtrans',`
+ gen_require(`
+ type bitcoin_t, bitcoin_exec_t;
+ ')
+
+ corecmd_search_bin($1)
+ domtrans_pattern($1, bitcoin_exec_t, bitcoin_t)
+')
+
+
+########################################
+## <summary>
+## Execute bitcoin server in the bitcoin domain.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access.
+## </summary>
+## </param>
+#
+interface(`bitcoin_initrc_domtrans',`
+ gen_require(`
+ type bitcoin_initrc_exec_t;
+ ')
+
+ init_labeled_script_domtrans($1, bitcoin_initrc_exec_t)
+')
+
+
+########################################
+## <summary>
+## Search bitcoin lib directories.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access.
+## </summary>
+## </param>
+#
+interface(`bitcoin_search_lib',`
+ gen_require(`
+ type bitcoin_var_lib_t;
+ ')
+
+ allow $1 bitcoin_var_lib_t:dir search_dir_perms;
+ files_search_var_lib($1)
+')
+
+########################################
+## <summary>
+## Read bitcoin lib files.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access.
+## </summary>
+## </param>
+#
+interface(`bitcoin_read_lib_files',`
+ gen_require(`
+ type bitcoin_var_lib_t;
+ ')
+
+ files_search_var_lib($1)
+ read_files_pattern($1, bitcoin_var_lib_t, bitcoin_var_lib_t)
+')
+
+########################################
+## <summary>
+## Manage bitcoin lib files.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access.
+## </summary>
+## </param>
+#
+interface(`bitcoin_manage_lib_files',`
+ gen_require(`
+ type bitcoin_var_lib_t;
+ ')
+
+ files_search_var_lib($1)
+ manage_files_pattern($1, bitcoin_var_lib_t, bitcoin_var_lib_t)
+')
+
+########################################
+## <summary>
+## Manage bitcoin lib directories.
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access.
+## </summary>
+## </param>
+#
+interface(`bitcoin_manage_lib_dirs',`
+ gen_require(`
+ type bitcoin_var_lib_t;
+ ')
+
+ files_search_var_lib($1)
+ manage_dirs_pattern($1, bitcoin_var_lib_t, bitcoin_var_lib_t)
+')
+
+
+########################################
+## <summary>
+## All of the rules required to administrate
+## an bitcoin environment
+## </summary>
+## <param name="domain">
+## <summary>
+## Domain allowed access.
+## </summary>
+## </param>
+## <param name="role">
+## <summary>
+## Role allowed access.
+## </summary>
+## </param>
+## <rolecap/>
+#
+interface(`bitcoin_admin',`
+ gen_require(`
+ type bitcoin_t;
+ type bitcoin_initrc_exec_t;
+ type bitcoin_var_lib_t;
+ ')
+
+ allow $1 bitcoin_t:process { ptrace signal_perms };
+ ps_process_pattern($1, bitcoin_t)
+
+ bitcoin_initrc_domtrans($1)
+ domain_system_change_exemption($1)
+ role_transition $2 bitcoin_initrc_exec_t system_r;
+ allow $2 system_r;
+
+ files_search_var_lib($1)
+ admin_pattern($1, bitcoin_var_lib_t)
+
+')
+
diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec
new file mode 100644
index 0000000000..38ae038180
--- /dev/null
+++ b/contrib/rpm/bitcoin.spec
@@ -0,0 +1,444 @@
+%define bdbv 4.8.30
+%global selinux_variants mls strict targeted
+
+%if 0%{?_no_gui:1}
+%define _buildqt 0
+%define buildargs --with-gui=no
+%else
+%define _buildqt 1
+%if 0%{?_use_qt4}
+%define buildargs --with-qrencode --with-gui=qt4
+%else
+%define buildargs --with-qrencode --with-gui=qt5
+%endif
+%endif
+
+Name: bitcoin
+Version: 0.12.0
+Release: 2%{?dist}
+Summary: Peer to Peer Cryptographic Currency
+
+Group: Applications/System
+License: MIT
+URL: https://bitcoin.org/
+Source0: https://bitcoin.org/bin/bitcoin-core-%{version}/bitcoin-%{version}.tar.gz
+Source1: http://download.oracle.com/berkeley-db/db-%{bdbv}.NC.tar.gz
+
+Source10: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/examples/bitcoin.conf
+
+#man pages
+Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoind.1
+Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-cli.1
+Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-qt.1
+Source23: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin.conf.5
+
+#selinux
+Source30: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.te
+# Source31 - what about bitcoin-tx and bench_bitcoin ???
+Source31: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.fc
+Source32: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.if
+
+Source100: https://upload.wikimedia.org/wikipedia/commons/4/46/Bitcoin.svg
+
+%if 0%{?_use_libressl:1}
+BuildRequires: libressl-devel
+%else
+BuildRequires: openssl-devel
+%endif
+BuildRequires: boost-devel
+BuildRequires: miniupnpc-devel
+BuildRequires: autoconf automake libtool
+BuildRequires: libevent-devel
+
+
+Patch0: bitcoin-0.12.0-libressl.patch
+
+
+%description
+Bitcoin is a digital cryptographic currency that uses peer-to-peer technology to
+operate with no central authority or banks; managing transactions and the
+issuing of bitcoins is carried out collectively by the network.
+
+%if %{_buildqt}
+%package core
+Summary: Peer to Peer Cryptographic Currency
+Group: Applications/System
+Obsoletes: %{name} < %{version}-%{release}
+Provides: %{name} = %{version}-%{release}
+%if 0%{?_use_qt4}
+BuildRequires: qt-devel
+%else
+BuildRequires: qt5-qtbase-devel
+# for /usr/bin/lrelease-qt5
+BuildRequires: qt5-linguist
+%endif
+BuildRequires: protobuf-devel
+BuildRequires: qrencode-devel
+BuildRequires: %{_bindir}/desktop-file-validate
+# for icon generation from SVG
+BuildRequires: %{_bindir}/inkscape
+BuildRequires: %{_bindir}/convert
+
+%description core
+Bitcoin is a digital cryptographic currency that uses peer-to-peer technology to
+operate with no central authority or banks; managing transactions and the
+issuing of bitcoins is carried out collectively by the network.
+
+This package contains the Qt based graphical client and node. If you are looking
+to run a Bitcoin wallet, this is probably the package you want.
+%endif
+
+
+%package libs
+Summary: Bitcoin shared libraries
+Group: System Environment/Libraries
+
+%description libs
+This package provides the bitcoinconsensus shared libraries. These libraries
+may be used by third party software to provide consensus verification
+functionality.
+
+Unless you know need this package, you probably do not.
+
+%package devel
+Summary: Development files for bitcoin
+Group: Development/Libraries
+Requires: %{name}-libs = %{version}-%{release}
+
+%description devel
+This package contains the header files and static library for the
+bitcoinconsensus shared library. If you are developing or compiling software
+that wants to link against that library, then you need this package installed.
+
+Most people do not need this package installed.
+
+%package server
+Summary: The bitcoin daemon
+Group: System Environment/Daemons
+Requires: bitcoin-utils = %{version}-%{release}
+Requires: selinux-policy policycoreutils-python
+Requires(pre): shadow-utils
+Requires(post): %{_sbindir}/semodule %{_sbindir}/restorecon %{_sbindir}/fixfiles %{_sbindir}/sestatus
+Requires(postun): %{_sbindir}/semodule %{_sbindir}/restorecon %{_sbindir}/fixfiles %{_sbindir}/sestatus
+BuildRequires: systemd
+BuildRequires: checkpolicy
+BuildRequires: %{_datadir}/selinux/devel/Makefile
+
+%description server
+This package provides a stand-alone bitcoin-core daemon. For most users, this
+package is only needed if they need a full-node without the graphical client.
+
+Some third party wallet software will want this package to provide the actual
+bitcoin-core node they use to connect to the network.
+
+If you use the graphical bitcoin-core client then you almost certainly do not
+need this package.
+
+%package utils
+Summary: Bitcoin utilities
+Group: Applications/System
+
+%description utils
+This package provides several command line utilities for interacting with a
+bitcoin-core daemon.
+
+The bitcoin-cli utility allows you to communicate and control a bitcoin daemon
+over RPC, the bitcoin-tx utility allows you to create a custom transaction, and
+the bench_bitcoin utility can be used to perform some benchmarks.
+
+This package contains utilities needed by the bitcoin-server package.
+
+
+%prep
+%setup -q
+%patch0 -p1 -b .libressl
+cp -p %{SOURCE10} ./bitcoin.conf.example
+tar -zxf %{SOURCE1}
+cp -p db-%{bdbv}.NC/LICENSE ./db-%{bdbv}.NC-LICENSE
+mkdir db4 SELinux
+cp -p %{SOURCE30} %{SOURCE31} %{SOURCE32} SELinux/
+
+
+%build
+CWD=`pwd`
+cd db-%{bdbv}.NC/build_unix/
+../dist/configure --enable-cxx --disable-shared --with-pic --prefix=${CWD}/db4
+make install
+cd ../..
+
+./autogen.sh
+%configure LDFLAGS="-L${CWD}/db4/lib/" CPPFLAGS="-I${CWD}/db4/include/" --with-miniupnpc --enable-glibc-back-compat %{buildargs}
+make %{?_smp_mflags}
+
+pushd SELinux
+for selinuxvariant in %{selinux_variants}; do
+ make NAME=${selinuxvariant} -f %{_datadir}/selinux/devel/Makefile
+ mv bitcoin.pp bitcoin.pp.${selinuxvariant}
+ make NAME=${selinuxvariant} -f %{_datadir}/selinux/devel/Makefile clean
+done
+popd
+
+
+%install
+make install DESTDIR=%{buildroot}
+
+mkdir -p -m755 %{buildroot}%{_sbindir}
+mv %{buildroot}%{_bindir}/bitcoind %{buildroot}%{_sbindir}/bitcoind
+
+# systemd stuff
+mkdir -p %{buildroot}%{_tmpfilesdir}
+cat <<EOF > %{buildroot}%{_tmpfilesdir}/bitcoin.conf
+d /run/bitcoind 0750 bitcoin bitcoin -
+EOF
+touch -a -m -t 201504280000 %{buildroot}%{_tmpfilesdir}/bitcoin.conf
+
+mkdir -p %{buildroot}%{_sysconfdir}/sysconfig
+cat <<EOF > %{buildroot}%{_sysconfdir}/sysconfig/bitcoin
+# Provide options to the bitcoin daemon here, for example
+# OPTIONS="-testnet -disable-wallet"
+
+OPTIONS=""
+
+# System service defaults.
+# Don't change these unless you know what you're doing.
+CONFIG_FILE="%{_sysconfdir}/bitcoin/bitcoin.conf"
+DATA_DIR="%{_localstatedir}/lib/bitcoin"
+PID_FILE="/run/bitcoind/bitcoind.pid"
+EOF
+touch -a -m -t 201504280000 %{buildroot}%{_sysconfdir}/sysconfig/bitcoin
+
+mkdir -p %{buildroot}%{_unitdir}
+cat <<EOF > %{buildroot}%{_unitdir}/bitcoin.service
+[Unit]
+Description=Bitcoin daemon
+After=syslog.target network.target
+
+[Service]
+Type=forking
+ExecStart=%{_sbindir}/bitcoind -daemon -conf=\${CONFIG_FILE} -datadir=\${DATA_DIR} -pid=\${PID_FILE} \$OPTIONS
+EnvironmentFile=%{_sysconfdir}/sysconfig/bitcoin
+User=bitcoin
+Group=bitcoin
+
+Restart=on-failure
+PrivateTmp=true
+TimeoutStopSec=120
+TimeoutStartSec=60
+StartLimitInterval=240
+StartLimitBurst=5
+
+[Install]
+WantedBy=multi-user.target
+EOF
+touch -a -m -t 201504280000 %{buildroot}%{_unitdir}/bitcoin.service
+#end systemd stuff
+
+mkdir %{buildroot}%{_sysconfdir}/bitcoin
+mkdir -p %{buildroot}%{_localstatedir}/lib/bitcoin
+
+#SELinux
+for selinuxvariant in %{selinux_variants}; do
+ install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant}
+ install -p -m 644 SELinux/bitcoin.pp.${selinuxvariant} %{buildroot}%{_datadir}/selinux/${selinuxvariant}/bitcoin.pp
+done
+
+%if %{_buildqt}
+# qt icons
+install -D -p share/pixmaps/bitcoin.ico %{buildroot}%{_datadir}/pixmaps/bitcoin.ico
+install -p share/pixmaps/nsis-header.bmp %{buildroot}%{_datadir}/pixmaps/
+install -p share/pixmaps/nsis-wizard.bmp %{buildroot}%{_datadir}/pixmaps/
+install -p %{SOURCE100} %{buildroot}%{_datadir}/pixmaps/bitcoin.svg
+%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin16.png -w16 -h16
+%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin32.png -w32 -h32
+%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin64.png -w64 -h64
+%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin128.png -w128 -h128
+%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/bitcoin256.png -w256 -h256
+%{_bindir}/convert -resize 16x16 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin16.xpm
+%{_bindir}/convert -resize 32x32 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin32.xpm
+%{_bindir}/convert -resize 64x64 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin64.xpm
+%{_bindir}/convert -resize 128x128 %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin128.xpm
+%{_bindir}/convert %{buildroot}%{_datadir}/pixmaps/bitcoin256.png %{buildroot}%{_datadir}/pixmaps/bitcoin256.xpm
+touch %{buildroot}%{_datadir}/pixmaps/*.png -r %{SOURCE100}
+touch %{buildroot}%{_datadir}/pixmaps/*.xpm -r %{SOURCE100}
+
+# Desktop File - change the touch timestamp if modifying
+mkdir -p %{buildroot}%{_datadir}/applications
+cat <<EOF > %{buildroot}%{_datadir}/applications/bitcoin-core.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=Bitcoin
+Comment=Bitcoin P2P Cryptocurrency
+Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair
+Comment[tr]=Bitcoin, eÅŸten eÅŸe kriptografik sanal para birimi
+Exec=bitcoin-qt %u
+Terminal=false
+Type=Application
+Icon=bitcoin128
+MimeType=x-scheme-handler/bitcoin;
+Categories=Office;Finance;
+EOF
+# change touch date when modifying desktop
+touch -a -m -t 201511100546 %{buildroot}%{_datadir}/applications/bitcoin-core.desktop
+%{_bindir}/desktop-file-validate %{buildroot}%{_datadir}/applications/bitcoin-core.desktop
+
+# KDE protocol - change the touch timestamp if modifying
+mkdir -p %{buildroot}%{_datadir}/kde4/services
+cat <<EOF > %{buildroot}%{_datadir}/kde4/services/bitcoin-core.protocol
+[Protocol]
+exec=bitcoin-qt '%u'
+protocol=bitcoin
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+EOF
+# change touch date when modifying protocol
+touch -a -m -t 201511100546 %{buildroot}%{_datadir}/kde4/services/bitcoin-core.protocol
+%endif
+
+# man pages
+install -D -p %{SOURCE20} %{buildroot}%{_mandir}/man1/bitcoind.1
+install -p %{SOURCE21} %{buildroot}%{_mandir}/man1/bitcoin-cli.1
+%if %{_buildqt}
+install -p %{SOURCE22} %{buildroot}%{_mandir}/man1/bitcoin-qt.1
+%endif
+install -D -p %{SOURCE23} %{buildroot}%{_mandir}/man5/bitcoin.conf.5
+
+# nuke these, we do extensive testing of binaries in %%check before packaging
+rm -f %{buildroot}%{_bindir}/test_*
+
+%check
+make check
+pushd src
+srcdir=. test/bitcoin-util-test.py
+popd
+qa/pull-tester/rpc-tests.py -extended
+
+%post libs -p /sbin/ldconfig
+
+%postun libs -p /sbin/ldconfig
+
+%pre server
+getent group bitcoin >/dev/null || groupadd -r bitcoin
+getent passwd bitcoin >/dev/null ||
+ useradd -r -g bitcoin -d /var/lib/bitcoin -s /sbin/nologin \
+ -c "Bitcoin wallet server" bitcoin
+exit 0
+
+%post server
+%systemd_post bitcoin.service
+# SELinux
+if [ `%{_sbindir}/sestatus |grep -c "disabled"` -eq 0 ]; then
+for selinuxvariant in %{selinux_variants}; do
+ %{_sbindir}/semodule -s ${selinuxvariant} -i %{_datadir}/selinux/${selinuxvariant}/bitcoin.pp &> /dev/null || :
+done
+%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 8332
+%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 8333
+%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18332
+%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18333
+%{_sbindir}/fixfiles -R bitcoin-server restore &> /dev/null || :
+%{_sbindir}/restorecon -R %{_localstatedir}/lib/bitcoin || :
+fi
+
+%posttrans server
+%{_bindir}/systemd-tmpfiles --create
+
+%preun server
+%systemd_preun bitcoin.service
+
+%postun server
+%systemd_postun bitcoin.service
+# SELinux
+if [ $1 -eq 0 ]; then
+ if [ `%{_sbindir}/sestatus |grep -c "disabled"` -eq 0 ]; then
+ %{_sbindir}/semanage port -d -p tcp 8332
+ %{_sbindir}/semanage port -d -p tcp 8333
+ %{_sbindir}/semanage port -d -p tcp 18332
+ %{_sbindir}/semanage port -d -p tcp 18333
+ for selinuxvariant in %{selinux_variants}; do
+ %{_sbindir}/semodule -s ${selinuxvariant} -r bitcoin &> /dev/null || :
+ done
+ %{_sbindir}/fixfiles -R bitcoin-server restore &> /dev/null || :
+ [ -d %{_localstatedir}/lib/bitcoin ] && \
+ %{_sbindir}/restorecon -R %{_localstatedir}/lib/bitcoin &> /dev/null || :
+ fi
+fi
+
+%clean
+rm -rf %{buildroot}
+
+%if %{_buildqt}
+%files core
+%defattr(-,root,root,-)
+%license COPYING db-%{bdbv}.NC-LICENSE
+%doc COPYING bitcoin.conf.example doc/README.md doc/bips.md doc/files.md doc/multiwallet-qt.md doc/reduce-traffic.md doc/release-notes.md doc/tor.md
+%attr(0755,root,root) %{_bindir}/bitcoin-qt
+%attr(0644,root,root) %{_datadir}/applications/bitcoin-core.desktop
+%attr(0644,root,root) %{_datadir}/kde4/services/bitcoin-core.protocol
+%attr(0644,root,root) %{_datadir}/pixmaps/*.ico
+%attr(0644,root,root) %{_datadir}/pixmaps/*.bmp
+%attr(0644,root,root) %{_datadir}/pixmaps/*.svg
+%attr(0644,root,root) %{_datadir}/pixmaps/*.png
+%attr(0644,root,root) %{_datadir}/pixmaps/*.xpm
+%attr(0644,root,root) %{_mandir}/man1/bitcoin-qt.1*
+%endif
+
+%files libs
+%defattr(-,root,root,-)
+%license COPYING
+%doc COPYING doc/README.md doc/shared-libraries.md
+%{_libdir}/lib*.so.*
+
+%files devel
+%defattr(-,root,root,-)
+%license COPYING
+%doc COPYING doc/README.md doc/developer-notes.md doc/shared-libraries.md
+%attr(0644,root,root) %{_includedir}/*.h
+%{_libdir}/*.so
+%{_libdir}/*.a
+%{_libdir}/*.la
+%attr(0644,root,root) %{_libdir}/pkgconfig/*.pc
+
+%files server
+%defattr(-,root,root,-)
+%license COPYING db-%{bdbv}.NC-LICENSE
+%doc COPYING bitcoin.conf.example doc/README.md doc/REST-interface.md doc/bips.md doc/dnsseed-policy.md doc/files.md doc/reduce-traffic.md doc/release-notes.md doc/tor.md
+%attr(0755,root,root) %{_sbindir}/bitcoind
+%attr(0644,root,root) %{_tmpfilesdir}/bitcoin.conf
+%attr(0644,root,root) %{_unitdir}/bitcoin.service
+%dir %attr(0750,bitcoin,bitcoin) %{_sysconfdir}/bitcoin
+%dir %attr(0750,bitcoin,bitcoin) %{_localstatedir}/lib/bitcoin
+%config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/bitcoin
+%attr(0644,root,root) %{_datadir}/selinux/*/*.pp
+%attr(0644,root,root) %{_mandir}/man1/bitcoind.1*
+%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5*
+
+%files utils
+%defattr(-,root,root,-)
+%license COPYING
+%doc COPYING bitcoin.conf.example doc/README.md
+%attr(0755,root,root) %{_bindir}/bitcoin-cli
+%attr(0755,root,root) %{_bindir}/bitcoin-tx
+%attr(0755,root,root) %{_bindir}/bench_bitcoin
+%attr(0644,root,root) %{_mandir}/man1/bitcoin-cli.1*
+%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5*
+
+
+
+%changelog
+* Fri Feb 26 2016 Alice Wonder <buildmaster@librelamp.com> - 0.12.0-2
+- Rename Qt package from bitcoin to bitcoin-core
+- Make building of the Qt package optional
+- When building the Qt package, default to Qt5 but allow building
+- against Qt4
+- Only run SELinux stuff in post scripts if it is not set to disabled
+
+* Wed Feb 24 2016 Alice Wonder <buildmaster@librelamp.com> - 0.12.0-1
+- Initial spec file for 0.12.0 release
+
+# This spec file is written from scratch but a lot of the packaging decisions are directly
+# based upon the 0.11.2 package spec file from https://www.ringingliberty.com/bitcoin/
diff --git a/contrib/rpm/bitcoin.te b/contrib/rpm/bitcoin.te
new file mode 100644
index 0000000000..d6231c591a
--- /dev/null
+++ b/contrib/rpm/bitcoin.te
@@ -0,0 +1,81 @@
+policy_module(bitcoin, 1.100.1)
+
+########################################
+#
+# Declarations
+#
+
+type bitcoin_t;
+type bitcoin_exec_t;
+init_daemon_domain(bitcoin_t, bitcoin_exec_t)
+
+permissive bitcoin_t;
+
+type bitcoin_initrc_exec_t;
+init_script_file(bitcoin_initrc_exec_t)
+
+type bitcoin_conf_t;
+files_type(bitcoin_conf_t)
+
+type bitcoin_var_lib_t;
+files_type(bitcoin_var_lib_t)
+
+type bitcoin_var_run_t;
+files_type(bitcoin_var_run_t)
+
+type bitcoin_port_t;
+corenet_port(bitcoin_port_t)
+
+########################################
+#
+# bitcoin local policy
+#
+allow bitcoin_t self:process { fork };
+
+allow bitcoin_t self:fifo_file rw_fifo_file_perms;
+allow bitcoin_t self:unix_stream_socket create_stream_socket_perms;
+
+manage_dirs_pattern(bitcoin_t, bitcoin_conf_t, bitcoin_conf_t)
+manage_files_pattern(bitcoin_t, bitcoin_conf_t, bitcoin_conf_t)
+
+manage_dirs_pattern(bitcoin_t, bitcoin_var_lib_t, bitcoin_var_lib_t)
+manage_files_pattern(bitcoin_t, bitcoin_var_lib_t, bitcoin_var_lib_t)
+files_var_lib_filetrans(bitcoin_t, bitcoin_var_lib_t, { dir file })
+
+manage_dirs_pattern(bitcoin_t, bitcoin_var_run_t, bitcoin_var_run_t)
+manage_files_pattern(bitcoin_t, bitcoin_var_run_t, bitcoin_var_run_t)
+
+sysnet_dns_name_resolve(bitcoin_t)
+corenet_all_recvfrom_unlabeled(bitcoin_t)
+
+allow bitcoin_t self:tcp_socket create_stream_socket_perms;
+corenet_tcp_sendrecv_generic_if(bitcoin_t)
+corenet_tcp_sendrecv_generic_node(bitcoin_t)
+corenet_tcp_sendrecv_all_ports(bitcoin_t)
+corenet_tcp_bind_generic_node(bitcoin_t)
+
+gen_require(`
+ type bitcoin_port_t;
+')
+allow bitcoin_t bitcoin_port_t:tcp_socket name_bind;
+
+gen_require(`
+ type bitcoin_port_t;
+')
+allow bitcoin_t bitcoin_port_t:tcp_socket name_connect;
+
+domain_use_interactive_fds(bitcoin_t)
+
+files_read_etc_files(bitcoin_t)
+
+miscfiles_read_localization(bitcoin_t)
+
+sysnet_dns_name_resolve(bitcoin_t)
+
+allow bitcoin_t bitcoin_exec_t:file execute_no_trans;
+allow bitcoin_t self:process setsched;
+corecmd_exec_ls(bitcoin_t)
+corenet_tcp_connect_http_port(bitcoin_t)
+dev_read_urand(bitcoin_t)
+fs_getattr_xattr_fs(bitcoin_t)
+kernel_read_system_state(bitcoin_t)
diff --git a/depends/config.guess b/depends/config.guess
index fba6e87a0f..373a659a06 100755
--- a/depends/config.guess
+++ b/depends/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2015 Free Software Foundation, Inc.
+# Copyright 1992-2016 Free Software Foundation, Inc.
-timestamp='2015-11-19'
+timestamp='2016-02-11'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ timestamp='2015-11-19'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
#
# Please send patches to <config-patches@gnu.org>.
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2015 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -237,6 +237,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+ exit ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
@@ -268,42 +272,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"EV4.5 (21064)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"LCA4 (21066/21068)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"EV5 (21164)")
- UNAME_MACHINE="alphaev5" ;;
+ UNAME_MACHINE=alphaev5 ;;
"EV5.6 (21164A)")
- UNAME_MACHINE="alphaev56" ;;
+ UNAME_MACHINE=alphaev56 ;;
"EV5.6 (21164PC)")
- UNAME_MACHINE="alphapca56" ;;
+ UNAME_MACHINE=alphapca56 ;;
"EV5.7 (21164PC)")
- UNAME_MACHINE="alphapca57" ;;
+ UNAME_MACHINE=alphapca57 ;;
"EV6 (21264)")
- UNAME_MACHINE="alphaev6" ;;
+ UNAME_MACHINE=alphaev6 ;;
"EV6.7 (21264A)")
- UNAME_MACHINE="alphaev67" ;;
+ UNAME_MACHINE=alphaev67 ;;
"EV6.8CB (21264C)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.8AL (21264B)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.8CX (21264D)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.9A (21264/EV69A)")
- UNAME_MACHINE="alphaev69" ;;
+ UNAME_MACHINE=alphaev69 ;;
"EV7 (21364)")
- UNAME_MACHINE="alphaev7" ;;
+ UNAME_MACHINE=alphaev7 ;;
"EV7.9 (21364A)")
- UNAME_MACHINE="alphaev79" ;;
+ UNAME_MACHINE=alphaev79 ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@@ -376,16 +380,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
- SUN_ARCH="i386"
+ SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
- SUN_ARCH="x86_64"
+ SUN_ARCH=x86_64
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -410,7 +414,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
@@ -635,13 +639,13 @@ EOF
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;;
esac
fi
@@ -684,7 +688,7 @@ EOF
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ ${HP_ARCH} = "hppa2.0w" ]
+ if [ ${HP_ARCH} = hppa2.0w ]
then
eval $set_cc_for_build
@@ -700,9 +704,9 @@ EOF
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
- HP_ARCH="hppa2.0w"
+ HP_ARCH=hppa2.0w
else
- HP_ARCH="hppa64"
+ HP_ARCH=hppa64
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -807,14 +811,14 @@ EOF
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -919,7 +923,7 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
- if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
@@ -1285,7 +1289,7 @@ EOF
UNAME_PROCESSOR=powerpc
fi
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
@@ -1309,7 +1313,7 @@ EOF
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = "x86"; then
+ if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
@@ -1340,7 +1344,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
- if test "$cputype" = "386"; then
+ if test "$cputype" = 386; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
@@ -1394,7 +1398,7 @@ EOF
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
amd64:Isilon\ OneFS:*:*)
- echo x86_64-unknown-onefs
+ echo x86_64-unknown-onefs
exit ;;
esac
@@ -1405,9 +1409,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
diff --git a/depends/config.sub b/depends/config.sub
index ea8747d30f..6223dde931 100755
--- a/depends/config.sub
+++ b/depends/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2015 Free Software Foundation, Inc.
+# Copyright 1992-2016 Free Software Foundation, Inc.
-timestamp='2015-11-22'
+timestamp='2016-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ timestamp='2015-11-22'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2015 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -520,7 +520,7 @@ case $basic_machine in
basic_machine=i386-pc
os=-aros
;;
- asmjs)
+ asmjs)
basic_machine=asmjs-unknown
;;
aux)
@@ -1382,7 +1382,7 @@ case $os in
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -bitrig* | -openbsd* | -solidbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk
index 3d5a6df974..45fa03631f 100644
--- a/depends/packages/miniupnpc.mk
+++ b/depends/packages/miniupnpc.mk
@@ -1,8 +1,8 @@
package=miniupnpc
-$(package)_version=1.9.20151026
+$(package)_version=1.9.20160209
$(package)_download_path=http://miniupnp.free.fr/files
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=f3cf9a5a31588a917d4d9237e5bc50f84d00c5aa48e27ed50d9b88dfa6a25d47
+$(package)_sha256_hash=572171eacc1d72537ce47b6f4571260757ab7bcfdaf54c3a55c7f88594d94b6f
define $(package)_set_vars
$(package)_build_opts=CC="$($(package)_cc)"
diff --git a/doc/bips.md b/doc/bips.md
index e73add0130..b8efabbcf2 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -17,6 +17,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**):
* [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124).
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
* [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)).
-* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, but only enforced for peer versions `>=70011` as of **v0.12.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579)).
+* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)).
* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)).
+* [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)).
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 707f2357f8..806d174ebf 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -51,6 +51,17 @@ The following outputs are affected by this change:
### P2P protocol and network code
+The p2p alert system has been removed in #7692 and the 'alert' message is no longer supported.
+
+
+Fee filtering of invs (BIP 133)
+------------------------------------
+
+The optional new p2p message "feefilter" is implemented and the protocol
+version is bumped to 70013. Upon receiving a feefilter message from a peer,
+a node will not send invs for any transactions which do not meet the filter
+feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki)
+
### Validation
### Build system
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index b32d8d93a9..d794dbe806 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -117,6 +117,7 @@ testScripts = [
'invalidtxrequest.py',
'abandonconflict.py',
'p2p-versionbits-warning.py',
+ 'importprunedfunds.py',
]
testScriptsExt = [
'bip9-softforks.py',
@@ -129,7 +130,6 @@ testScriptsExt = [
'getblocktemplate_proposals.py',
'txn_doublespend.py',
'txn_clone.py --mineblock',
- 'pruning.py',
'forknotify.py',
'invalidateblock.py',
# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
@@ -139,6 +139,8 @@ testScriptsExt = [
'mempool_packages.py',
'maxuploadtarget.py',
'replace-by-fee.py',
+ 'p2p-feefilter.py',
+ 'pruning.py', # leave pruning last as it takes a REALLY long time
]
#Enable ZMQ tests
diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py
index 38028df079..a83aa97fcd 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/qa/rpc-tests/abandonconflict.py
@@ -83,6 +83,12 @@ class AbandonConflictTest(BitcoinTestFramework):
# inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance()
assert(newbalance == balance - Decimal("24.9996"))
+ # Unconfirmed received funds that are not in mempool, also shouldn't show
+ # up in unconfirmed balance
+ unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
+ assert(unconfbalance == newbalance)
+ # Also shouldn't show up in listunspent
+ assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)])
balance = newbalance
# Abandon original transaction and verify inputs are available again
diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py
index 7045ae435c..272a5dc154 100755
--- a/qa/rpc-tests/blockchain.py
+++ b/qa/rpc-tests/blockchain.py
@@ -28,6 +28,7 @@ class BlockchainTest(BitcoinTestFramework):
Test blockchain-related RPC calls:
- gettxoutsetinfo
+ - verifychain
"""
@@ -44,6 +45,7 @@ class BlockchainTest(BitcoinTestFramework):
def run_test(self):
self._test_gettxoutsetinfo()
self._test_getblockheader()
+ self.nodes[0].verifychain(4, 0)
def _test_gettxoutsetinfo(self):
node = self.nodes[0]
diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py
index 6964348d55..5af8158467 100755
--- a/qa/rpc-tests/disablewallet.py
+++ b/qa/rpc-tests/disablewallet.py
@@ -29,5 +29,19 @@ class DisableWalletTest (BitcoinTestFramework):
x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
assert(x['isvalid'] == True)
+ # Checking mining to an address without a wallet
+ try:
+ self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
+ except JSONRPCException,e:
+ assert("Invalid address" not in e.error['message'])
+ assert("ProcessNewBlock, block not accepted" not in e.error['message'])
+ assert("Couldn't create new block" not in e.error['message'])
+
+ try:
+ self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
+ raise AssertionError("Must not mine to invalid address!")
+ except JSONRPCException,e:
+ assert("Invalid address" in e.error['message'])
+
if __name__ == '__main__':
DisableWalletTest ().main ()
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 0287965b97..4458712815 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -71,7 +71,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enought inputs
+ assert(len(dec_tx['vin']) > 0) #test if we have enought inputs
##############################
# simple test with two coins #
@@ -84,7 +84,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enough inputs
+ assert(len(dec_tx['vin']) > 0) #test if we have enough inputs
##############################
# simple test with two coins #
@@ -97,7 +97,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- assert_equal(len(dec_tx['vin']) > 0, True)
+ assert(len(dec_tx['vin']) > 0)
assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')
@@ -116,7 +116,7 @@ class RawTransactionsTest(BitcoinTestFramework):
for out in dec_tx['vout']:
totalOut += out['value']
- assert_equal(len(dec_tx['vin']) > 0, True)
+ assert(len(dec_tx['vin']) > 0)
assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')
@@ -130,7 +130,7 @@ class RawTransactionsTest(BitcoinTestFramework):
utx = aUtx
break
- assert_equal(utx!=False, True)
+ assert(utx!=False)
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
outputs = { self.nodes[0].getnewaddress() : 1.0 }
@@ -159,7 +159,7 @@ class RawTransactionsTest(BitcoinTestFramework):
utx = aUtx
break
- assert_equal(utx!=False, True)
+ assert(utx!=False)
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance }
@@ -189,7 +189,7 @@ class RawTransactionsTest(BitcoinTestFramework):
utx = aUtx
break
- assert_equal(utx!=False, True)
+ assert(utx!=False)
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
outputs = { self.nodes[0].getnewaddress() : 1.0 }
@@ -234,7 +234,7 @@ class RawTransactionsTest(BitcoinTestFramework):
utx2 = aUtx
- assert_equal(utx!=False, True)
+ assert(utx!=False)
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]
outputs = { self.nodes[0].getnewaddress() : 6.0 }
@@ -276,7 +276,7 @@ class RawTransactionsTest(BitcoinTestFramework):
utx2 = aUtx
- assert_equal(utx!=False, True)
+ assert(utx!=False)
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]
outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 }
@@ -306,14 +306,11 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
- errorString = ""
try:
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
+ raise AssertionError("Spent more than available")
except JSONRPCException,e:
- errorString = e.error['message']
-
- assert("Insufficient" in errorString)
-
+ assert("Insufficient" in e.error['message'])
############################################################
@@ -462,12 +459,11 @@ class RawTransactionsTest(BitcoinTestFramework):
self.is_network_split=False
self.sync_all()
- error = False
try:
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
- except:
- error = True
- assert(error)
+ raise AssertionError("Wallet unlocked without passphrase")
+ except JSONRPCException as e:
+ assert('walletpassphrase' in e.error['message'])
oldBalance = self.nodes[0].getbalance()
@@ -580,7 +576,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(len(res_dec["vin"]), 1)
assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)
- assert_equal("fee" in result.keys(), True)
+ assert("fee" in result.keys())
assert_greater_than(result["changepos"], -1)
###############################################################
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
index f83b5f140d..d2cb4ab8d6 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -120,10 +120,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
# Test 3: Truncated final tx
lastbyte = txlist[-1].pop()
- try:
- assert_template(node, tmpl, txlist, 'n/a')
- except JSONRPCException:
- pass # Expected
+ assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a')
txlist[-1].append(lastbyte)
# Test 4: Add an invalid tx to the end (duplicate of gen tx)
@@ -144,10 +141,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
# Test 7: Bad tx count
txlist.append(b'')
- try:
- assert_template(node, tmpl, txlist, 'n/a')
- except JSONRPCException:
- pass # Expected
+ assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a')
txlist.pop()
# Test 8: Bad bits
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index eb548aee9d..c231676ec8 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -37,14 +37,14 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True)
- assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open!
+ assert('"error":null' in out1)
+ assert(conn.sock!=None) #according to http/1.1 connection must still be open!
#send 2nd request without closing connection
conn.request('POST', '/', '{"method": "getchaintips"}', headers)
out2 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message
- assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open!
+ assert('"error":null' in out1) #must also response with a correct json-rpc message
+ assert(conn.sock!=None) #according to http/1.1 connection must still be open!
conn.close()
#same should be if we add keep-alive because this should be the std. behaviour
@@ -54,14 +54,14 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True)
- assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open!
+ assert('"error":null' in out1)
+ assert(conn.sock!=None) #according to http/1.1 connection must still be open!
#send 2nd request without closing connection
conn.request('POST', '/', '{"method": "getchaintips"}', headers)
out2 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message
- assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open!
+ assert('"error":null' in out1) #must also response with a correct json-rpc message
+ assert(conn.sock!=None) #according to http/1.1 connection must still be open!
conn.close()
#now do the same with "Connection: close"
@@ -71,8 +71,8 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True)
- assert_equal(conn.sock!=None, False) #now the connection must be closed after the response
+ assert('"error":null' in out1)
+ assert(conn.sock==None) #now the connection must be closed after the response
#node1 (2nd node) is running with disabled keep-alive option
urlNode1 = urlparse.urlparse(self.nodes[1].url)
@@ -83,7 +83,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True)
+ assert('"error":null' in out1)
#node2 (third node) is running with standard keep-alive parameters which means keep-alive is on
urlNode2 = urlparse.urlparse(self.nodes[2].url)
@@ -94,8 +94,8 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert_equal('"error":null' in out1, True)
- assert_equal(conn.sock!=None, True) #connection must be closed because bitcoind should use keep-alive by default
+ assert('"error":null' in out1)
+ assert(conn.sock!=None) #connection must be closed because bitcoind should use keep-alive by default
# Check excessive request size
conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port)
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
new file mode 100755
index 0000000000..5cbdcde9aa
--- /dev/null
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python2
+# 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.
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import decimal
+
+class ImportPrunedFundsTest(BitcoinTestFramework):
+
+ def setup_chain(self):
+ print("Initializing test directory "+self.options.tmpdir)
+ initialize_chain_clean(self.options.tmpdir, 4)
+
+ def setup_network(self, split=False):
+ self.nodes = start_nodes(2, self.options.tmpdir)
+ connect_nodes_bi(self.nodes,0,1)
+ self.is_network_split=False
+ self.sync_all()
+
+ def run_test (self):
+ import time
+ begintime = int(time.time())
+
+ print "Mining blocks..."
+ self.nodes[0].generate(101)
+
+ # sync
+ self.sync_all()
+
+ # address
+ address1 = self.nodes[0].getnewaddress()
+ # pubkey
+ address2 = self.nodes[0].getnewaddress()
+ address2_pubkey = self.nodes[0].validateaddress(address2)['pubkey'] # Using pubkey
+ # privkey
+ address3 = self.nodes[0].getnewaddress()
+ address3_privkey = self.nodes[0].dumpprivkey(address3) # Using privkey
+
+ #Check only one address
+ address_info = self.nodes[0].validateaddress(address1)
+ assert_equal(address_info['ismine'], True)
+
+ self.sync_all()
+
+ #Node 1 sync test
+ assert_equal(self.nodes[1].getblockcount(),101)
+
+ #Address Test - before import
+ address_info = self.nodes[1].validateaddress(address1)
+ assert_equal(address_info['iswatchonly'], False)
+ assert_equal(address_info['ismine'], False)
+
+ address_info = self.nodes[1].validateaddress(address2)
+ assert_equal(address_info['iswatchonly'], False)
+ assert_equal(address_info['ismine'], False)
+
+ address_info = self.nodes[1].validateaddress(address3)
+ assert_equal(address_info['iswatchonly'], False)
+ assert_equal(address_info['ismine'], False)
+
+ #Send funds to self
+ txnid1 = self.nodes[0].sendtoaddress(address1, 0.1)
+ self.nodes[0].generate(1)
+ rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex']
+ proof1 = self.nodes[0].gettxoutproof([txnid1])
+
+ txnid2 = self.nodes[0].sendtoaddress(address2, 0.05)
+ self.nodes[0].generate(1)
+ rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']
+ proof2 = self.nodes[0].gettxoutproof([txnid2])
+
+
+ txnid3 = self.nodes[0].sendtoaddress(address3, 0.025)
+ self.nodes[0].generate(1)
+ rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']
+ proof3 = self.nodes[0].gettxoutproof([txnid3])
+
+ self.sync_all()
+
+ #Import with no affiliated address
+ try:
+ result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "")
+ except JSONRPCException,e:
+ errorString = e.error['message']
+
+ assert('No addresses' in errorString)
+
+ balance1 = self.nodes[1].getbalance("", 0, True)
+ assert_equal(balance1, Decimal(0))
+
+ #Import with affiliated address with no rescan
+ self.nodes[1].importaddress(address2, "", False)
+ result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "")
+ balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ assert_equal(balance2, Decimal('0.05'))
+
+ #Import with private key with no rescan
+ self.nodes[1].importprivkey(address3_privkey, "", False)
+ result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "")
+ balance3 = Decimal(self.nodes[1].getbalance("", 0, False))
+ assert_equal(balance3, Decimal('0.025'))
+ balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ assert_equal(balance3, Decimal('0.075'))
+
+ #Addresses Test - after import
+ address_info = self.nodes[1].validateaddress(address1)
+ assert_equal(address_info['iswatchonly'], False)
+ assert_equal(address_info['ismine'], False)
+ address_info = self.nodes[1].validateaddress(address2)
+ assert_equal(address_info['iswatchonly'], True)
+ assert_equal(address_info['ismine'], False)
+ address_info = self.nodes[1].validateaddress(address3)
+ assert_equal(address_info['iswatchonly'], False)
+ assert_equal(address_info['ismine'], True)
+
+ #Remove transactions
+
+ try:
+ self.nodes[1].removeprunedfunds(txnid1)
+ except JSONRPCException,e:
+ errorString = e.error['message']
+
+ assert('does not exist' in errorString)
+
+ balance1 = Decimal(self.nodes[1].getbalance("", 0, True))
+ assert_equal(balance1, Decimal('0.075'))
+
+
+ self.nodes[1].removeprunedfunds(txnid2)
+ balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ assert_equal(balance2, Decimal('0.025'))
+
+ self.nodes[1].removeprunedfunds(txnid3)
+ balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ assert_equal(balance3, Decimal('0.0'))
+
+if __name__ == '__main__':
+ ImportPrunedFundsTest ().main ()
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index 2517bed470..e4127500cd 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -7,7 +7,6 @@
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-from test_framework.comptool import wait_until
import time
'''
diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
index 7914ceea22..c19a63c699 100755
--- a/qa/rpc-tests/mempool_limit.py
+++ b/qa/rpc-tests/mempool_limit.py
@@ -38,7 +38,6 @@ class MempoolLimitTest(BitcoinTestFramework):
self.nodes[0].settxfee(0) # return to automatic fee selection
txFS = self.nodes[0].signrawtransaction(txF['hex'])
txid = self.nodes[0].sendrawtransaction(txFS['hex'])
- self.nodes[0].lockunspent(True, [us0])
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
base_fee = relayfee*100
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 6109cb026c..bc3f9e051c 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -7,6 +7,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+from test_framework.mininode import COIN
MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py
new file mode 100755
index 0000000000..f85c18dcd5
--- /dev/null
+++ b/qa/rpc-tests/p2p-feefilter.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python2
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT/X11 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 *
+import time
+
+'''
+FeeFilterTest -- test processing of feefilter messages
+'''
+
+def hashToHex(hash):
+ return format(hash, '064x').decode('utf-8')
+
+# Wait up to 60 secs to see if the testnode has received all the expected invs
+def allInvsMatch(invsExpected, testnode):
+ for x in xrange(60):
+ with mininode_lock:
+ if (sorted(invsExpected) == sorted(testnode.txinvs)):
+ return True;
+ time.sleep(1)
+ return False;
+
+# TestNode: bare-bones "peer". Used to track which invs are received from a node
+# and to send the node feefilter messages.
+class TestNode(SingleNodeConnCB):
+ def __init__(self):
+ SingleNodeConnCB.__init__(self)
+ self.txinvs = []
+
+ def on_inv(self, conn, message):
+ for i in message.inv:
+ if (i.type == 1):
+ self.txinvs.append(hashToHex(i.hash))
+
+ def clear_invs(self):
+ with mininode_lock:
+ self.txinvs = []
+
+ def send_filter(self, feerate):
+ self.send_message(msg_feefilter(feerate))
+ self.sync_with_ping()
+
+class FeeFilterTest(BitcoinTestFramework):
+ def setup_network(self):
+ # Node1 will be used to generate txs which should be relayed from Node0
+ # to our test node
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"]))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"]))
+ connect_nodes(self.nodes[0], 1)
+
+ def run_test(self):
+ node1 = self.nodes[1]
+ # Get out of IBD
+ node1.generate(1)
+ sync_blocks(self.nodes)
+
+ # Setup the p2p connections and start up the network thread.
+ test_node = TestNode()
+ connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)
+ test_node.add_connection(connection)
+ NetworkThread().start()
+ test_node.wait_for_verack()
+
+ # Test that invs are received for all txs at feerate of 20 sat/byte
+ node1.settxfee(Decimal("0.00020000"))
+ txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
+ assert(allInvsMatch(txids, test_node))
+ test_node.clear_invs()
+
+ # Set a filter of 15 sat/byte
+ test_node.send_filter(15000)
+
+ # Test that txs are still being received (paying 20 sat/byte)
+ txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
+ assert(allInvsMatch(txids, test_node))
+ test_node.clear_invs()
+
+ # Change tx fee rate to 10 sat/byte and test they are no longer received
+ node1.settxfee(Decimal("0.00010000"))
+ [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
+ sync_mempools(self.nodes) # must be sure node 0 has received all txs
+ time.sleep(10) # wait 10 secs to be sure its doesn't relay any
+ assert(allInvsMatch([], test_node))
+ test_node.clear_invs()
+
+ # Remove fee filter and check that txs are received again
+ test_node.send_filter(0)
+ txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
+ assert(allInvsMatch(txids, test_node))
+ test_node.clear_invs()
+
+if __name__ == '__main__':
+ FeeFilterTest().main()
diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py
index fba469a0dd..1eb2772592 100644
--- a/qa/rpc-tests/test_framework/authproxy.py
+++ b/qa/rpc-tests/test_framework/authproxy.py
@@ -61,7 +61,7 @@ class JSONRPCException(Exception):
def EncodeDecimal(o):
if isinstance(o, decimal.Decimal):
- return round(o, 8)
+ return str(o)
raise TypeError(repr(o) + " is not JSON serializable")
class AuthServiceProxy(object):
@@ -92,11 +92,10 @@ class AuthServiceProxy(object):
self.__conn = connection
elif self.__url.scheme == 'https':
self.__conn = httplib.HTTPSConnection(self.__url.hostname, port,
- None, None, False,
- timeout)
+ timeout=timeout)
else:
self.__conn = httplib.HTTPConnection(self.__url.hostname, port,
- False, timeout)
+ timeout=timeout)
def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'):
diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py
index d8fcd807f6..f19edbf069 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/qa/rpc-tests/test_framework/comptool.py
@@ -27,20 +27,6 @@ generator that returns TestInstance objects. See below for definition.
global mininode_lock
-def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
- attempt = 0
- elapsed = 0
-
- while attempt < attempts and elapsed < timeout:
- with mininode_lock:
- if predicate():
- return True
- attempt += 1
- elapsed += 0.05
- time.sleep(0.05)
-
- return False
-
class RejectResult(object):
'''
Outcome that expects rejection of a transaction or block.
diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py
index 934d0c7a75..20386c642c 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -1008,6 +1008,37 @@ class msg_reject(object):
return "msg_reject: %s %d %s [%064x]" \
% (self.message, self.code, self.reason, self.data)
+# Helper function
+def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
+ attempt = 0
+ elapsed = 0
+
+ while attempt < attempts and elapsed < timeout:
+ with mininode_lock:
+ if predicate():
+ return True
+ attempt += 1
+ elapsed += 0.05
+ time.sleep(0.05)
+
+ return False
+
+class msg_feefilter(object):
+ command = "feefilter"
+
+ def __init__(self, feerate=0L):
+ self.feerate = feerate
+
+ def deserialize(self, f):
+ self.feerate = struct.unpack("<Q", f.read(8))[0]
+
+ def serialize(self):
+ r = ""
+ r += struct.pack("<Q", self.feerate)
+ return r
+
+ def __repr__(self):
+ return "msg_feefilter(feerate=%08x)" % self.feerate
# This is what a callback should look like for NodeConn
# Reimplement the on_* functions to provide handling for events
@@ -1084,7 +1115,34 @@ class NodeConnCB(object):
def on_close(self, conn): pass
def on_mempool(self, conn): pass
def on_pong(self, conn, message): pass
+ def on_feefilter(self, conn, message): pass
+# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
+class SingleNodeConnCB(NodeConnCB):
+ def __init__(self):
+ NodeConnCB.__init__(self)
+ self.connection = None
+ self.ping_counter = 1
+ self.last_pong = msg_pong()
+
+ def add_connection(self, conn):
+ self.connection = conn
+
+ # Wrapper for the NodeConn's send_message function
+ def send_message(self, message):
+ self.connection.send_message(message)
+
+ def on_pong(self, conn, message):
+ self.last_pong = message
+
+ # Sync up with the node
+ def sync_with_ping(self, timeout=30):
+ def received_pong():
+ return (self.last_pong.nonce == self.ping_counter)
+ self.send_message(msg_ping(nonce=self.ping_counter))
+ success = wait_until(received_pong, timeout)
+ self.ping_counter += 1
+ return success
# The actual NodeConn class
# This class provides an interface for a p2p connection to a specified node
@@ -1105,7 +1163,8 @@ class NodeConn(asyncore.dispatcher):
"headers": msg_headers,
"getheaders": msg_getheaders,
"reject": msg_reject,
- "mempool": msg_mempool
+ "mempool": msg_mempool,
+ "feefilter": msg_feefilter
}
MAGIC_BYTES = {
"mainnet": "\xf9\xbe\xb4\xd9", # mainnet
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 8d4bd52b94..f069c32a60 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -16,6 +16,7 @@ import shutil
import subprocess
import time
import re
+import errno
from . import coverage
from .authproxy import AuthServiceProxy, JSONRPCException
@@ -130,11 +131,33 @@ def initialize_datadir(dirname, n):
f.write("listenonion=0\n")
return datadir
+def rpc_url(i, rpchost=None):
+ return "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
+
+def wait_for_bitcoind_start(process, url, i):
+ '''
+ Wait for bitcoind to start. This means that RPC is accessible and fully initialized.
+ Raise an exception if bitcoind exits during initialization.
+ '''
+ while True:
+ if process.poll() is not None:
+ raise Exception('bitcoind exited with status %i during initialization' % process.returncode)
+ try:
+ rpc = get_rpc_proxy(url, i)
+ blocks = rpc.getblockcount()
+ break # break out of loop on success
+ except IOError as e:
+ if e.errno != errno.ECONNREFUSED: # Port not yet open?
+ raise # unknown IO error
+ except JSONRPCException as e: # Initialization phase
+ if e.error['code'] != -28: # RPC in warmup?
+ raise # unkown JSON RPC exception
+ time.sleep(0.25)
+
def initialize_chain(test_dir):
"""
Create (or copy from cache) a 200-block-long chain and
4 wallets.
- bitcoind and bitcoin-cli must be in search path.
"""
if (not os.path.isdir(os.path.join("cache","node0"))
@@ -147,7 +170,6 @@ def initialize_chain(test_dir):
if os.path.isdir(os.path.join("cache","node"+str(i))):
shutil.rmtree(os.path.join("cache","node"+str(i)))
- devnull = open(os.devnull, "w")
# Create cache directories, run bitcoinds:
for i in range(4):
datadir=initialize_datadir("cache", i)
@@ -156,19 +178,15 @@ def initialize_chain(test_dir):
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
bitcoind_processes[i] = subprocess.Popen(args)
if os.getenv("PYTHON_DEBUG", ""):
- print "initialize_chain: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
- subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir,
- "-rpcwait", "getblockcount"], stdout=devnull)
+ print "initialize_chain: bitcoind started, waiting for RPC to come up"
+ wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i)
if os.getenv("PYTHON_DEBUG", ""):
- print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed"
- devnull.close()
+ print "initialize_chain: RPC succesfully started"
rpcs = []
-
for i in range(4):
try:
- url = "http://rt:rt@127.0.0.1:%d" % (rpc_port(i),)
- rpcs.append(get_rpc_proxy(url, i))
+ rpcs.append(get_rpc_proxy(rpc_url(i), i))
except:
sys.stderr.write("Error connecting to "+url+"\n")
sys.exit(1)
@@ -243,17 +261,12 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ]
if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args)
- devnull = open(os.devnull, "w")
if os.getenv("PYTHON_DEBUG", ""):
- print "start_node: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
- subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir] +
- _rpchost_to_args(rpchost) +
- ["-rpcwait", "getblockcount"], stdout=devnull)
+ print "start_node: bitcoind started, waiting for RPC to come up"
+ url = rpc_url(i, rpchost)
+ wait_for_bitcoind_start(bitcoind_processes[i], url, i)
if os.getenv("PYTHON_DEBUG", ""):
- print "start_node: calling bitcoin-cli -rpcwait getblockcount returned"
- devnull.close()
- url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
-
+ print "start_node: RPC succesfully started"
proxy = get_rpc_proxy(url, i, timeout=timewait)
if COVERAGE_DIR:
@@ -267,7 +280,14 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
"""
if extra_args is None: extra_args = [ None for i in range(num_nodes) ]
if binary is None: binary = [ None for i in range(num_nodes) ]
- return [ start_node(i, dirname, extra_args[i], rpchost, binary=binary[i]) for i in range(num_nodes) ]
+ rpcs = []
+ try:
+ for i in range(num_nodes):
+ rpcs.append(start_node(i, dirname, extra_args[i], rpchost, binary=binary[i]))
+ except: # If one node failed to start, stop the others
+ stop_nodes(rpcs)
+ raise
+ return rpcs
def log_filename(dirname, n_node, logname):
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 3cd495deb6..e6ce397119 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -59,6 +59,15 @@ class WalletTest (BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
+ # Exercise locking of unspent outputs
+ unspent_0 = self.nodes[2].listunspent()[0]
+ unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
+ self.nodes[2].lockunspent(False, [unspent_0])
+ assert_raises(JSONRPCException, self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
+ assert_equal([unspent_0], self.nodes[2].listlockunspent())
+ self.nodes[2].lockunspent(True, [unspent_0])
+ assert_equal(len(self.nodes[2].listlockunspent()), 0)
+
# Have node1 generate 100 blocks (so node0 can recover the fee)
self.nodes[1].generate(100)
self.sync_all()
@@ -148,6 +157,10 @@ class WalletTest (BitcoinTestFramework):
assert(txid1 in self.nodes[3].getrawmempool())
+ # Exercise balance rpcs
+ assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1)
+ assert_equal(self.nodes[0].getunconfirmedbalance(), 1)
+
#check if we can list zero value tx as available coins
#1. create rawtx
#2. hex-changed one output to 0.0
@@ -239,7 +252,7 @@ class WalletTest (BitcoinTestFramework):
except JSONRPCException,e:
errorString = e.error['message']
- assert_equal("Invalid amount" in errorString, True)
+ assert("Invalid amount" in errorString)
errorString = ""
try:
@@ -247,13 +260,26 @@ class WalletTest (BitcoinTestFramework):
except JSONRPCException,e:
errorString = e.error['message']
- assert_equal("not an integer" in errorString, True)
+ assert("not an integer" in errorString)
+
+ # Mine a block from node0 to an address from node1
+ cbAddr = self.nodes[1].getnewaddress()
+ blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0]
+ cbTxId = self.nodes[0].getblock(blkHash)['tx'][0]
+ self.sync_all()
+
+ # Check that the txid and balance is found by node1
+ try:
+ self.nodes[1].gettransaction(cbTxId)
+ except JSONRPCException,e:
+ assert("Invalid or non-wallet transaction id" not in e.error['message'])
#check if wallet or blochchain maintenance changes the balance
self.sync_all()
- self.nodes[0].generate(1)
+ blocks = self.nodes[0].generate(2)
self.sync_all()
balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
+ block_count = self.nodes[0].getblockcount()
maintenance = [
'-rescan',
@@ -267,8 +293,17 @@ class WalletTest (BitcoinTestFramework):
stop_nodes(self.nodes)
wait_bitcoinds()
self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3)
+ while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
+ # reindex will leave rpc warm up "early"; Wait for it to finish
+ time.sleep(0.1)
assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
+ # Exercise listsinceblock with the last two blocks
+ coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])
+ assert_equal(coinbase_tx_1["lastblock"], blocks[1])
+ assert_equal(len(coinbase_tx_1["transactions"]), 1)
+ assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1])
+ assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
if __name__ == '__main__':
WalletTest ().main ()
diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py
index 1ee0f79ac0..1ba4ded249 100755
--- a/qa/rpc-tests/zapwallettxes.py
+++ b/qa/rpc-tests/zapwallettxes.py
@@ -65,14 +65,8 @@ class ZapWalletTXesTest (BitcoinTestFramework):
#restart bitcoind with zapwallettxes
self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"])
- aException = False
- try:
- tx3 = self.nodes[0].gettransaction(txid3)
- except JSONRPCException,e:
- print e
- aException = True
-
- assert_equal(aException, True) #there must be a expection because the unconfirmed wallettx0 must be gone by now
+ assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3])
+ #there must be a expection because the unconfirmed wallettx0 must be gone by now
tx0 = self.nodes[0].gettransaction(txid0)
assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 2a6e4b930c..7728a43775 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -1,8 +1,9 @@
#!/usr/bin/python
'''
-Extract _("...") strings for translation and convert to Qt4 stringdefs so that
+Extract _("...") strings for translation and convert to Qt stringdefs so that
they can be picked up by Qt linguist.
'''
+from __future__ import division,print_function,unicode_literals
from subprocess import Popen, PIPE
import glob
import operator
@@ -52,10 +53,14 @@ files = sys.argv[1:]
# xgettext -n --keyword=_ $FILES
XGETTEXT=os.getenv('XGETTEXT', 'xgettext')
+if not XGETTEXT:
+ print('Cannot extract strings: xgettext utility is not installed or not configured.',file=sys.stderr)
+ print('Please install package "gettext" and re-run \'./configure\'.',file=sys.stderr)
+ exit(1)
child = Popen([XGETTEXT,'--output=-','-n','--keyword=_'] + files, stdout=PIPE)
(out, err) = child.communicate()
-messages = parse_po(out)
+messages = parse_po(out.decode('utf-8'))
f = open(OUT_CPP, 'w')
f.write("""
diff --git a/src/Makefile.am b/src/Makefile.am
index 7765ea43ed..6ad7aabae0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,7 +87,6 @@ endif
# bitcoin core #
BITCOIN_CORE_H = \
addrman.h \
- alert.h \
base58.h \
bloom.h \
chain.h \
@@ -176,7 +175,6 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
- alert.cpp \
bloom.cpp \
chain.cpp \
checkpoints.cpp \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index ca4e1e70d0..357e4c47ff 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -391,7 +391,7 @@ SECONDARY: $(QT_QM)
qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES)
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
- $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" ../share/qt/extract_strings_qt.py $^
+ $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
translate: qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM)
@test -n $(LUPDATE) || echo "lupdate is required for updating translations"
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 57f9ac50e0..d806fb219e 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -29,7 +29,7 @@ JSON_TEST_FILES = \
test/data/tx_valid.json \
test/data/sighash.json
-RAW_TEST_FILES = test/data/alertTests.raw
+RAW_TEST_FILES =
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
@@ -38,6 +38,7 @@ BITCOIN_TESTS =\
test/scriptnum10.h \
test/addrman_tests.cpp \
test/alert_tests.cpp \
+ test/amount_tests.cpp \
test/allocator_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
@@ -129,7 +130,7 @@ bitcoin_test_clean : FORCE
check-local:
@echo "Running test/bitcoin-util-test.py..."
- $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py
+ $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/bitcoin-util-test.py
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
if EMBEDDED_UNIVALUE
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
diff --git a/src/alert.cpp b/src/alert.cpp
deleted file mode 100644
index eb1cd5e7f6..0000000000
--- a/src/alert.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "alert.h"
-
-#include "clientversion.h"
-#include "net.h"
-#include "pubkey.h"
-#include "timedata.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <map>
-
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/replace.hpp>
-#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-
-using namespace std;
-
-map<uint256, CAlert> mapAlerts;
-CCriticalSection cs_mapAlerts;
-
-void CUnsignedAlert::SetNull()
-{
- nVersion = 1;
- nRelayUntil = 0;
- nExpiration = 0;
- nID = 0;
- nCancel = 0;
- setCancel.clear();
- nMinVer = 0;
- nMaxVer = 0;
- setSubVer.clear();
- nPriority = 0;
-
- strComment.clear();
- strStatusBar.clear();
- strReserved.clear();
-}
-
-std::string CUnsignedAlert::ToString() const
-{
- std::string strSetCancel;
- BOOST_FOREACH(int n, setCancel)
- strSetCancel += strprintf("%d ", n);
- std::string strSetSubVer;
- BOOST_FOREACH(const std::string& str, setSubVer)
- strSetSubVer += "\"" + str + "\" ";
- return strprintf(
- "CAlert(\n"
- " nVersion = %d\n"
- " nRelayUntil = %d\n"
- " nExpiration = %d\n"
- " nID = %d\n"
- " nCancel = %d\n"
- " setCancel = %s\n"
- " nMinVer = %d\n"
- " nMaxVer = %d\n"
- " setSubVer = %s\n"
- " nPriority = %d\n"
- " strComment = \"%s\"\n"
- " strStatusBar = \"%s\"\n"
- ")\n",
- nVersion,
- nRelayUntil,
- nExpiration,
- nID,
- nCancel,
- strSetCancel,
- nMinVer,
- nMaxVer,
- strSetSubVer,
- nPriority,
- strComment,
- strStatusBar);
-}
-
-void CAlert::SetNull()
-{
- CUnsignedAlert::SetNull();
- vchMsg.clear();
- vchSig.clear();
-}
-
-bool CAlert::IsNull() const
-{
- return (nExpiration == 0);
-}
-
-uint256 CAlert::GetHash() const
-{
- return Hash(this->vchMsg.begin(), this->vchMsg.end());
-}
-
-bool CAlert::IsInEffect() const
-{
- return (GetAdjustedTime() < nExpiration);
-}
-
-bool CAlert::Cancels(const CAlert& alert) const
-{
- if (!IsInEffect())
- return false; // this was a no-op before 31403
- return (alert.nID <= nCancel || setCancel.count(alert.nID));
-}
-
-bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
-{
- // TODO: rework for client-version-embedded-in-strSubVer ?
- return (IsInEffect() &&
- nMinVer <= nVersion && nVersion <= nMaxVer &&
- (setSubVer.empty() || setSubVer.count(strSubVerIn)));
-}
-
-bool CAlert::AppliesToMe() const
-{
- return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
-}
-
-bool CAlert::RelayTo(CNode* pnode) const
-{
- if (!IsInEffect())
- return false;
- // don't relay to nodes which haven't sent their version message
- if (pnode->nVersion == 0)
- return false;
- // returns true if wasn't already contained in the set
- if (pnode->setKnown.insert(GetHash()).second)
- {
- if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
- AppliesToMe() ||
- GetAdjustedTime() < nRelayUntil)
- {
- pnode->PushMessage(NetMsgType::ALERT, *this);
- return true;
- }
- }
- return false;
-}
-
-bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
-{
- CPubKey key(alertKey);
- if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
- return error("CAlert::CheckSignature(): verify signature failed");
-
- // Now unserialize the data
- CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
- sMsg >> *(CUnsignedAlert*)this;
- return true;
-}
-
-CAlert CAlert::getAlertByHash(const uint256 &hash)
-{
- CAlert retval;
- {
- LOCK(cs_mapAlerts);
- map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
- if(mi != mapAlerts.end())
- retval = mi->second;
- }
- return retval;
-}
-
-bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
-{
- if (!CheckSignature(alertKey))
- return false;
- if (!IsInEffect())
- return false;
-
- // alert.nID=max is reserved for if the alert key is
- // compromised. It must have a pre-defined message,
- // must never expire, must apply to all versions,
- // and must cancel all previous
- // alerts or it will be ignored (so an attacker can't
- // send an "everything is OK, don't panic" version that
- // cannot be overridden):
- int maxInt = std::numeric_limits<int>::max();
- if (nID == maxInt)
- {
- if (!(
- nExpiration == maxInt &&
- nCancel == (maxInt-1) &&
- nMinVer == 0 &&
- nMaxVer == maxInt &&
- setSubVer.empty() &&
- nPriority == maxInt &&
- strStatusBar == "URGENT: Alert key compromised, upgrade required"
- ))
- return false;
- }
-
- {
- LOCK(cs_mapAlerts);
- // Cancel previous alerts
- for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
- {
- const CAlert& alert = (*mi).second;
- if (Cancels(alert))
- {
- LogPrint("alert", "cancelling alert %d\n", alert.nID);
- uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
- mapAlerts.erase(mi++);
- }
- else if (!alert.IsInEffect())
- {
- LogPrint("alert", "expiring alert %d\n", alert.nID);
- uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
- mapAlerts.erase(mi++);
- }
- else
- mi++;
- }
-
- // Check if this alert has been cancelled
- BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
- {
- const CAlert& alert = item.second;
- if (alert.Cancels(*this))
- {
- LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
- return false;
- }
- }
-
- // Add to mapAlerts
- mapAlerts.insert(make_pair(GetHash(), *this));
- // Notify UI and -alertnotify if it applies to me
- if(AppliesToMe())
- {
- uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
- Notify(strStatusBar, fThread);
- }
- }
-
- LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
- return true;
-}
-
-void
-CAlert::Notify(const std::string& strMessage, bool fThread)
-{
- std::string strCmd = GetArg("-alertnotify", "");
- if (strCmd.empty()) return;
-
- // Alert text should be plain ascii coming from a trusted source, but to
- // be safe we first strip anything not in safeChars, then add single quotes around
- // the whole string before passing it to the shell:
- std::string singleQuote("'");
- std::string safeStatus = SanitizeString(strMessage);
- safeStatus = singleQuote+safeStatus+singleQuote;
- boost::replace_all(strCmd, "%s", safeStatus);
-
- if (fThread)
- boost::thread t(runCommand, strCmd); // thread runs free
- else
- runCommand(strCmd);
-}
diff --git a/src/alert.h b/src/alert.h
deleted file mode 100644
index 8cb86e338c..0000000000
--- a/src/alert.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_ALERT_H
-#define BITCOIN_ALERT_H
-
-#include "serialize.h"
-#include "sync.h"
-
-#include <map>
-#include <set>
-#include <stdint.h>
-#include <string>
-
-class CAlert;
-class CNode;
-class uint256;
-
-extern std::map<uint256, CAlert> mapAlerts;
-extern CCriticalSection cs_mapAlerts;
-
-/** Alerts are for notifying old versions if they become too obsolete and
- * need to upgrade. The message is displayed in the status bar.
- * Alert messages are broadcast as a vector of signed data. Unserializing may
- * not read the entire buffer if the alert is for a newer version, but older
- * versions can still relay the original data.
- */
-class CUnsignedAlert
-{
-public:
- int nVersion;
- int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes
- int64_t nExpiration;
- int nID;
- int nCancel;
- std::set<int> setCancel;
- int nMinVer; // lowest version inclusive
- int nMaxVer; // highest version inclusive
- std::set<std::string> setSubVer; // empty matches all
- int nPriority;
-
- // Actions
- std::string strComment;
- std::string strStatusBar;
- std::string strReserved;
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(nRelayUntil);
- READWRITE(nExpiration);
- READWRITE(nID);
- READWRITE(nCancel);
- READWRITE(setCancel);
- READWRITE(nMinVer);
- READWRITE(nMaxVer);
- READWRITE(setSubVer);
- READWRITE(nPriority);
-
- READWRITE(LIMITED_STRING(strComment, 65536));
- READWRITE(LIMITED_STRING(strStatusBar, 256));
- READWRITE(LIMITED_STRING(strReserved, 256));
- }
-
- void SetNull();
-
- std::string ToString() const;
-};
-
-/** An alert is a combination of a serialized CUnsignedAlert and a signature. */
-class CAlert : public CUnsignedAlert
-{
-public:
- std::vector<unsigned char> vchMsg;
- std::vector<unsigned char> vchSig;
-
- CAlert()
- {
- SetNull();
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(vchMsg);
- READWRITE(vchSig);
- }
-
- void SetNull();
- bool IsNull() const;
- uint256 GetHash() const;
- bool IsInEffect() const;
- bool Cancels(const CAlert& alert) const;
- bool AppliesTo(int nVersion, const std::string& strSubVerIn) const;
- bool AppliesToMe() const;
- bool RelayTo(CNode* pnode) const;
- bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
- bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread
- static void Notify(const std::string& strMessage, bool fThread);
-
- /*
- * Get copy of (active) alert object by hash. Returns a null alert if it is not found.
- */
- static CAlert getAlertByHash(const uint256 &hash);
-};
-
-#endif // BITCOIN_ALERT_H
diff --git a/src/amount.cpp b/src/amount.cpp
index a3abd8cd83..68806ff062 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -19,10 +19,10 @@ CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
CAmount CFeeRate::GetFee(size_t nSize) const
{
- CAmount nFee = nSatoshisPerK*nSize / 1000;
+ CAmount nFee = nSatoshisPerK * nSize / 1000;
- if (nFee == 0 && nSatoshisPerK > 0)
- nFee = nSatoshisPerK;
+ if (nFee == 0 && nSize != 0 && nSatoshisPerK > 0)
+ nFee = CAmount(1);
return nFee;
}
diff --git a/src/amount.h b/src/amount.h
index a48b17d514..9aba6525c7 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -42,10 +42,14 @@ public:
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
CFeeRate(const CAmount& nFeePaid, size_t nSize);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
-
- CAmount GetFee(size_t size) const; // unit returned is satoshis
- CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes
-
+ /**
+ * Return the fee in satoshis for the given size in bytes.
+ */
+ CAmount GetFee(size_t size) const;
+ /**
+ * Return the fee in satoshis for a size of 1000 bytes
+ */
+ CAmount GetFeePerK() const { return GetFee(1000); }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
diff --git a/src/base58.cpp b/src/base58.cpp
index 5e26cf8d47..d81c26092c 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -68,26 +68,31 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
// Skip & count leading zeroes.
int zeroes = 0;
+ int length = 0;
while (pbegin != pend && *pbegin == 0) {
pbegin++;
zeroes++;
}
// Allocate enough space in big-endian base58 representation.
- std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
+ int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up.
+ std::vector<unsigned char> b58(size);
// Process the bytes.
while (pbegin != pend) {
int carry = *pbegin;
+ int i = 0;
// Apply "b58 = b58 * 256 + ch".
- for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
+ for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
carry += 256 * (*it);
*it = carry % 58;
carry /= 58;
}
+
assert(carry == 0);
+ length = i;
pbegin++;
}
// Skip leading zeroes in base58 result.
- std::vector<unsigned char>::iterator it = b58.begin();
+ std::vector<unsigned char>::iterator it = b58.begin() + (size - length);
while (it != b58.end() && *it == 0)
it++;
// Translate the result into a string.
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index f48937d67d..965d131695 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -101,7 +101,6 @@ public:
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9;
- vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333;
nPruneAfterHeight = 100000;
@@ -188,7 +187,6 @@ public:
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
pchMessageStart[3] = 0x07;
- vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
nDefaultPort = 18333;
nPruneAfterHeight = 1000;
diff --git a/src/chainparams.h b/src/chainparams.h
index 88bc666765..59202f548a 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -54,7 +54,6 @@ public:
const Consensus::Params& GetConsensus() const { return consensus; }
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
- const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
const CBlock& GenesisBlock() const { return genesis; }
@@ -80,8 +79,6 @@ protected:
Consensus::Params consensus;
CMessageHeader::MessageStartChars pchMessageStart;
- //! Raw pub key bytes for the broadcast alert signing key.
- std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds;
diff --git a/src/coincontrol.h b/src/coincontrol.h
index 9626ad2c5b..12fe9ce219 100644
--- a/src/coincontrol.h
+++ b/src/coincontrol.h
@@ -38,10 +38,9 @@ public:
return (setSelected.size() > 0);
}
- bool IsSelected(const uint256& hash, unsigned int n) const
+ bool IsSelected(const COutPoint& output) const
{
- COutPoint outpt(hash, n);
- return (setSelected.count(outpt) > 0);
+ return (setSelected.count(output) > 0);
}
void Select(const COutPoint& output)
diff --git a/src/init.cpp b/src/init.cpp
index a39256c6e3..0fb7146128 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -27,6 +27,7 @@
#include "script/standard.h"
#include "script/sigcache.h"
#include "scheduler.h"
+#include "timedata.h"
#include "txdb.h"
#include "txmempool.h"
#include "torcontrol.h"
@@ -315,7 +316,6 @@ std::string HelpMessage(HelpMessageMode mode)
string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("Print this help message and exit"));
strUsage += HelpMessageOpt("-version", _("Print version and exit"));
- strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
if (showDebug)
@@ -331,6 +331,7 @@ std::string HelpMessage(HelpMessageMode mode)
}
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
+ strUsage += HelpMessageOpt("-feefilter", strprintf(_("Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), DEFAULT_FEEFILTER));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
@@ -365,12 +366,11 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER));
+ strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT));
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS));
- if (showDebug)
- strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of bloom filters (default: %u)", DEFAULT_ENFORCENODEBLOOM));
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort()));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
@@ -1002,8 +1002,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
- fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
-
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
diff --git a/src/main.cpp b/src/main.cpp
index f74cb30574..dfd92fa8f0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,7 +6,6 @@
#include "main.h"
#include "addrman.h"
-#include "alert.h"
#include "arith_uint256.h"
#include "chainparams.h"
#include "checkpoints.h"
@@ -18,10 +17,12 @@
#include "init.h"
#include "merkleblock.h"
#include "net.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
+#include "random.h"
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
@@ -75,7 +76,6 @@ bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
-bool fAlerts = DEFAULT_ALERTS;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
@@ -83,6 +83,7 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
CTxMemPool mempool(::minRelayTxFee);
+FeeFilterRounder filterRounder(::minRelayTxFee);
struct COrphanTx {
CTransaction tx;
@@ -989,7 +990,7 @@ std::string FormatStateMessage(const CValidationState &state)
}
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee,
+ bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
std::vector<uint256>& vHashTxnToUncache)
{
const uint256 hash = tx.GetHash();
@@ -1146,6 +1147,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
unsigned int nSize = entry.GetTxSize();
+ if (txFeeRate) {
+ *txFeeRate = CFeeRate(nFees, nSize);
+ }
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
@@ -1394,10 +1398,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+ bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
{
std::vector<uint256> vHashTxToUncache;
- bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
+ bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
if (!res) {
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
pcoinsTip->Uncache(hashTx);
@@ -1566,6 +1570,26 @@ bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
+static void AlertNotify(const std::string& strMessage, bool fThread)
+{
+ uiInterface.NotifyAlertChanged();
+ std::string strCmd = GetArg("-alertnotify", "");
+ if (strCmd.empty()) return;
+
+ // Alert text should be plain ascii coming from a trusted source, but to
+ // be safe we first strip anything not in safeChars, then add single quotes around
+ // the whole string before passing it to the shell:
+ std::string singleQuote("'");
+ std::string safeStatus = SanitizeString(strMessage);
+ safeStatus = singleQuote+safeStatus+singleQuote;
+ boost::replace_all(strCmd, "%s", safeStatus);
+
+ if (fThread)
+ boost::thread t(runCommand, strCmd); // thread runs free
+ else
+ runCommand(strCmd);
+}
+
void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
@@ -1585,7 +1609,7 @@ void CheckForkWarningConditions()
{
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
- CAlert::Notify(warning, true);
+ AlertNotify(warning, true);
}
if (pindexBestForkTip && pindexBestForkBase)
{
@@ -2116,7 +2140,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
if (!strWarning.empty())
{
strMiscWarning = strWarning;
- CAlert::Notify(strWarning, true);
+ AlertNotify(strWarning, true);
lastAlertTime = now;
}
}
@@ -2552,7 +2576,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
if (state == THRESHOLD_ACTIVE) {
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
if (!fWarned) {
- CAlert::Notify(strMiscWarning, true);
+ AlertNotify(strMiscWarning, true);
fWarned = true;
}
} else {
@@ -2574,7 +2598,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
if (!fWarned) {
- CAlert::Notify(strMiscWarning, true);
+ AlertNotify(strMiscWarning, true);
fWarned = true;
}
}
@@ -2608,7 +2632,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) {
mempool.removeRecursive(tx, removed);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
@@ -4225,14 +4249,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
assert(nNodes == forward.size());
}
-//////////////////////////////////////////////////////////////////////////////
-//
-// CAlert
-//
-
std::string GetWarnings(const std::string& strFor)
{
- int nPriority = 0;
string strStatusBar;
string strRPC;
string strGUI;
@@ -4248,37 +4266,20 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
- nPriority = 1000;
strStatusBar = strGUI = strMiscWarning;
}
if (fLargeWorkForkFound)
{
- nPriority = 2000;
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
else if (fLargeWorkInvalidChainFound)
{
- nPriority = 2000;
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
- // Alerts
- {
- LOCK(cs_mapAlerts);
- BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
- {
- const CAlert& alert = item.second;
- if (alert.AppliesToMe() && alert.nPriority > nPriority)
- {
- nPriority = alert.nPriority;
- strStatusBar = strGUI = alert.strStatusBar;
- }
- }
- }
-
if (strFor == "gui")
return strGUI;
else if (strFor == "statusbar")
@@ -4494,7 +4495,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
Misbehaving(pfrom->GetId(), 100);
return false;
- } else if (GetBoolArg("-enforcenodebloom", DEFAULT_ENFORCENODEBLOOM)) {
+ } else {
pfrom->fDisconnect = true;
return false;
}
@@ -4600,13 +4601,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
- // Relay alerts
- {
- LOCK(cs_mapAlerts);
- BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
- item.second.RelayTo(pfrom);
- }
-
pfrom->fSuccessfullyConnected = true;
string remoteAddr;
@@ -4940,10 +4934,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->setAskFor.erase(inv.hash);
mapAlreadyAskedFor.erase(inv);
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
- {
+ CFeeRate txFeeRate = CFeeRate(0);
+ if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) {
mempool.check(pcoinsTip);
- RelayTransaction(tx);
+ RelayTransaction(tx, txFeeRate);
vWorkQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
@@ -4974,10 +4968,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (setMisbehaving.count(fromPeer))
continue;
- if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
- {
+ CFeeRate orphanFeeRate = CFeeRate(0);
+ if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx);
+ RelayTransaction(orphanTx, orphanFeeRate);
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
}
@@ -5030,7 +5024,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
- RelayTransaction(tx);
+ RelayTransaction(tx, txFeeRate);
} else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
}
@@ -5224,6 +5218,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
}
+ if (pfrom->minFeeFilter) {
+ CFeeRate feeRate;
+ mempool.lookupFeeRate(hash, feeRate);
+ LOCK(pfrom->cs_feeFilter);
+ if (feeRate.GetFeePerK() < pfrom->minFeeFilter)
+ continue;
+ }
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
pfrom->PushMessage(NetMsgType::INV, vInv);
@@ -5314,37 +5315,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (fAlerts && strCommand == NetMsgType::ALERT)
- {
- CAlert alert;
- vRecv >> alert;
-
- uint256 alertHash = alert.GetHash();
- if (pfrom->setKnown.count(alertHash) == 0)
- {
- if (alert.ProcessAlert(chainparams.AlertKey()))
- {
- // Relay
- pfrom->setKnown.insert(alertHash);
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- alert.RelayTo(pnode);
- }
- }
- else {
- // Small DoS penalty so peers that send us lots of
- // duplicate/expired/invalid-signature/whatever alerts
- // eventually get banned.
- // This isn't a Misbehaving(100) (immediate ban) because the
- // peer might be an older or different implementation with
- // a different signature key, etc.
- Misbehaving(pfrom->GetId(), 10);
- }
- }
- }
-
-
else if (strCommand == NetMsgType::FILTERLOAD)
{
CBloomFilter filter;
@@ -5417,8 +5387,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
- else
- {
+ else if (strCommand == NetMsgType::FEEFILTER) {
+ CAmount newFeeFilter = 0;
+ vRecv >> newFeeFilter;
+ if (MoneyRange(newFeeFilter)) {
+ {
+ LOCK(pfrom->cs_feeFilter);
+ pfrom->minFeeFilter = newFeeFilter;
+ }
+ LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id);
+ }
+ }
+
+ else {
// Ignore unknown commands for extensibility
LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
}
@@ -5900,6 +5881,29 @@ bool SendMessages(CNode* pto)
if (!vGetData.empty())
pto->PushMessage(NetMsgType::GETDATA, vGetData);
+ //
+ // Message: feefilter
+ //
+ // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
+ if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
+ CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
+ int64_t timeNow = GetTimeMicros();
+ if (timeNow > pto->nextSendTimeFeeFilter) {
+ CAmount filterToSend = filterRounder.round(currentFilter);
+ if (filterToSend != pto->lastSentFeeFilter) {
+ pto->PushMessage(NetMsgType::FEEFILTER, filterToSend);
+ pto->lastSentFeeFilter = filterToSend;
+ }
+ pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
+ }
+ // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
+ // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
+ else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
+ (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
+ pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
+ }
+ }
}
return true;
}
diff --git a/src/main.h b/src/main.h
index 6936b5379a..0bfcfab213 100644
--- a/src/main.h
+++ b/src/main.h
@@ -42,8 +42,6 @@ class CValidationState;
struct CNodeStateStats;
struct LockPoints;
-/** Default for accepting alerts from the P2P network. */
-static const bool DEFAULT_ALERTS = true;
/** Default for DEFAULT_WHITELISTRELAY. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for DEFAULT_WHITELISTFORCERELAY. */
@@ -104,6 +102,10 @@ static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
/** Average delay between trickled inventory broadcasts in seconds.
* Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
+/** Average delay between feefilter broadcasts in seconds. */
+static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
+/** Maximum feefilter broadcast delay after significant change. */
+static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
static const unsigned int DEFAULT_LIMITFREERELAY = 15;
static const bool DEFAULT_RELAYPRIORITY = true;
@@ -119,12 +121,13 @@ static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
static const bool DEFAULT_TESTSAFEMODE = false;
/** Default for -mempoolreplacement */
static const bool DEFAULT_ENABLE_REPLACEMENT = true;
+/** Default for using fee filter */
+static const bool DEFAULT_FEEFILTER = true;
/** Maximum number of headers to announce when relaying blocks with headers message.*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
-static const bool DEFAULT_ENFORCENODEBLOOM = false;
struct BlockHasher
{
@@ -155,7 +158,6 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */
extern CAmount maxTxFee;
-extern bool fAlerts;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
extern int64_t nMaxTipAge;
extern bool fEnableReplacement;
@@ -286,7 +288,7 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+ bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 8447f924e4..dca4973cc4 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -95,7 +95,7 @@ void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const st
}
}
-uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch) {
+uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
if (nBitsUsed >= vBits.size()) {
// overflowed the bits array - failure
fBad = true;
@@ -110,14 +110,16 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns
return uint256();
}
const uint256 &hash = vHash[nHashUsed++];
- if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid
+ if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid
vMatch.push_back(hash);
+ vnIndex.push_back(pos);
+ }
return hash;
} else {
// otherwise, descend into the subtrees to extract matched txids and hashes
- uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right;
+ uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right;
if (pos*2+1 < CalcTreeWidth(height-1)) {
- right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch);
+ right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex);
if (right == left) {
// The left and right branches should never be identical, as the transaction
// hashes covered by them must each be unique.
@@ -147,7 +149,7 @@ CPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const
CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
-uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
+uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
vMatch.clear();
// An empty set will not work
if (nTransactions == 0)
@@ -167,7 +169,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
nHeight++;
// traverse the partial tree
unsigned int nBitsUsed = 0, nHashUsed = 0;
- uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
+ uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex);
// verify that no problems occurred during the tree traversal
if (fBad)
return uint256();
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 996cd12624..835cbcce55 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -75,9 +75,9 @@ protected:
/**
* recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
- * it returns the hash of the respective node.
+ * it returns the hash of the respective node and its respective index.
*/
- uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
+ uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
public:
@@ -110,10 +110,11 @@ public:
CPartialMerkleTree();
/**
- * extract the matching txid's represented by this partial merkle tree.
+ * extract the matching txid's represented by this partial merkle tree
+ * and their respective indices within the partial tree.
* returns the merkle root, or 0 in case of failure
*/
- uint256 ExtractMatches(std::vector<uint256> &vMatch);
+ uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
};
diff --git a/src/net.cpp b/src/net.cpp
index b589692d1b..e8cc753a48 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2053,20 +2053,15 @@ public:
instance_of_cnetcleanup;
-
-
-
-
-
-void RelayTransaction(const CTransaction& tx)
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << tx;
- RelayTransaction(tx, ss);
+ RelayTransaction(tx, feerate, ss);
}
-void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss)
{
CInv inv(MSG_TX, tx.GetHash());
{
@@ -2087,6 +2082,11 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
{
if(!pnode->fRelayTxes)
continue;
+ {
+ LOCK(pnode->cs_feeFilter);
+ if (feerate.GetFeePerK() < pnode->minFeeFilter)
+ continue;
+ }
LOCK(pnode->cs_filter);
if (pnode->pfilter)
{
@@ -2390,6 +2390,10 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nPingUsecTime = 0;
fPingQueued = false;
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
+ minFeeFilter = 0;
+ lastSentFeeFilter = 0;
+ nextSendTimeFeeFilter = 0;
+
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
diff --git a/src/net.h b/src/net.h
index ec296e2aba..ab9eb68d85 100644
--- a/src/net.h
+++ b/src/net.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
+#include "amount.h"
#include "bloom.h"
#include "compat.h"
#include "limitedmap.h"
@@ -415,6 +416,11 @@ public:
int64_t nMinPingUsecTime;
// Whether a ping is requested.
bool fPingQueued;
+ // Minimum fee rate with which to filter inv's to this node
+ CAmount minFeeFilter;
+ CCriticalSection cs_feeFilter;
+ CAmount lastSentFeeFilter;
+ int64_t nextSendTimeFeeFilter;
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
@@ -766,8 +772,8 @@ public:
class CTransaction;
-void RelayTransaction(const CTransaction& tx);
-void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate);
+void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index de3c060d6a..7b0e8b7d08 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -8,6 +8,7 @@
#include "amount.h"
#include "primitives/transaction.h"
+#include "random.h"
#include "streams.h"
#include "txmempool.h"
#include "util.h"
@@ -580,3 +581,21 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein)
priStats.Read(filein);
nBestSeenHeight = nFileBestSeenHeight;
}
+
+FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
+{
+ CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2;
+ feeset.insert(0);
+ for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ feeset.insert(bucketBoundary);
+ }
+}
+
+CAmount FeeFilterRounder::round(CAmount currentMinFee)
+{
+ std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
+ if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) {
+ it--;
+ }
+ return *it;
+}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 3fa31c39e7..cdd984de7d 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -286,4 +286,17 @@ private:
CFeeRate feeLikely, feeUnlikely;
double priLikely, priUnlikely;
};
+
+class FeeFilterRounder
+{
+public:
+ /** Create new FeeFilterRounder */
+ FeeFilterRounder(const CFeeRate& minIncrementalFee);
+
+ /** Quantize a minimum fee for privacy purpose before broadcast **/
+ CAmount round(CAmount currentMinFee);
+
+private:
+ std::set<double> feeset;
+};
#endif /*BITCOIN_POLICYESTIMATOR_H */
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 9f7d6f3943..149816406a 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -34,7 +34,8 @@ public:
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
- return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
+ int cmp = a.hash.Compare(b.hash);
+ return cmp < 0 || (cmp == 0 && a.n < b.n);
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
diff --git a/src/protocol.cpp b/src/protocol.cpp
index c1c7c0b96b..8c4bd05725 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -28,13 +28,13 @@ const char *GETADDR="getaddr";
const char *MEMPOOL="mempool";
const char *PING="ping";
const char *PONG="pong";
-const char *ALERT="alert";
const char *NOTFOUND="notfound";
const char *FILTERLOAD="filterload";
const char *FILTERADD="filteradd";
const char *FILTERCLEAR="filterclear";
const char *REJECT="reject";
const char *SENDHEADERS="sendheaders";
+const char *FEEFILTER="feefilter";
};
static const char* ppszTypeName[] =
@@ -64,13 +64,13 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::MEMPOOL,
NetMsgType::PING,
NetMsgType::PONG,
- NetMsgType::ALERT,
NetMsgType::NOTFOUND,
NetMsgType::FILTERLOAD,
NetMsgType::FILTERADD,
NetMsgType::FILTERCLEAR,
NetMsgType::REJECT,
- NetMsgType::SENDHEADERS
+ NetMsgType::SENDHEADERS,
+ NetMsgType::FEEFILTER
};
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
diff --git a/src/protocol.h b/src/protocol.h
index c8b8d20ead..1b049e52af 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -164,13 +164,6 @@ extern const char *PING;
*/
extern const char *PONG;
/**
- * The alert message warns nodes of problems that may affect them or the rest
- * of the network.
- * @since protocol version 311.
- * @see https://bitcoin.org/en/developer-reference#alert
- */
-extern const char *ALERT;
-/**
* The notfound message is a reply to a getdata message which requested an
* object the receiving node does not have available for relay.
* @ince protocol version 70001.
@@ -218,7 +211,12 @@ extern const char *REJECT;
* @see https://bitcoin.org/en/developer-reference#sendheaders
*/
extern const char *SENDHEADERS;
-
+/**
+ * The feefilter message tells the receiving peer not to inv us any txs
+ * which do not meet the specified min fee rate.
+ * @since protocol version 70013 as described by BIP133
+ */
+extern const char *FEEFILTER;
};
/* Get a vector of all valid message types (see above) */
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index fb502b3c81..697736cc88 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -8,7 +8,6 @@
#include "guiconstants.h"
#include "peertablemodel.h"
-#include "alert.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
@@ -122,20 +121,8 @@ void ClientModel::updateNumConnections(int numConnections)
Q_EMIT numConnectionsChanged(numConnections);
}
-void ClientModel::updateAlert(const QString &hash, int status)
+void ClientModel::updateAlert()
{
- // Show error message notification for new alert
- if(status == CT_NEW)
- {
- uint256 hash_256;
- hash_256.SetHex(hash.toStdString());
- CAlert alert = CAlert::getAlertByHash(hash_256);
- if(!alert.IsNull())
- {
- Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
- }
- }
-
Q_EMIT alertsChanged(getStatusBarWarnings());
}
@@ -186,11 +173,6 @@ QString ClientModel::formatSubVersion() const
return QString::fromStdString(strSubVersion);
}
-QString ClientModel::formatBuildDate() const
-{
- return QString::fromStdString(CLIENT_DATE);
-}
-
bool ClientModel::isReleaseVersion() const
{
return CLIENT_VERSION_IS_RELEASE;
@@ -206,6 +188,11 @@ QString ClientModel::formatClientStartupTime() const
return QDateTime::fromTime_t(nClientStartupTime).toString();
}
+QString ClientModel::dataDir() const
+{
+ return QString::fromStdString(GetDataDir().string());
+}
+
void ClientModel::updateBanlist()
{
banTableModel->refresh();
@@ -227,12 +214,10 @@ static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConn
Q_ARG(int, newNumConnections));
}
-static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
+static void NotifyAlertChanged(ClientModel *clientmodel)
{
- qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status);
- QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
- Q_ARG(QString, QString::fromStdString(hash.GetHex())),
- Q_ARG(int, status));
+ qDebug() << "NotifyAlertChanged";
+ QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
}
static void BannedListChanged(ClientModel *clientmodel)
@@ -266,7 +251,7 @@ void ClientModel::subscribeToCoreSignals()
// Connect signals to client
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
- uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
+ uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
}
@@ -276,7 +261,7 @@ void ClientModel::unsubscribeFromCoreSignals()
// Disconnect signals from client
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
- uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
+ uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 62c9f71ac7..109f95a2a7 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -72,10 +72,10 @@ public:
QString formatFullVersion() const;
QString formatSubVersion() const;
- QString formatBuildDate() const;
bool isReleaseVersion() const;
QString clientName() const;
QString formatClientStartupTime() const;
+ QString dataDir() const;
private:
OptionsModel *optionsModel;
@@ -103,7 +103,7 @@ Q_SIGNALS:
public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
- void updateAlert(const QString &hash, int status);
+ void updateAlert();
void updateBanlist();
};
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 7393c83c7d..f909499952 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -796,7 +796,7 @@ void CoinControlDialog::updateView()
}
// set checkbox
- if (coinControl->IsSelected(txhash, out.i))
+ if (coinControl->IsSelected(COutPoint(txhash, out.i)))
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
}
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index a5ac0a7d26..c17efcf1b3 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -141,12 +141,12 @@
<item row="5" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
- <string>Build date</string>
+ <string>Datadir</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
- <widget class="QLabel" name="buildDate">
+ <widget class="QLabel" name="dataDir">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -156,6 +156,9 @@
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index e8ee3042db..42112c42f1 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -444,7 +444,7 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->clientVersion->setText(model->formatFullVersion());
ui->clientUserAgent->setText(model->formatSubVersion());
ui->clientName->setText(model->clientName());
- ui->buildDate->setText(model->formatBuildDate());
+ ui->dataDir->setText(model->dataDir());
ui->startupTime->setText(model->formatClientStartupTime());
ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 5cb4cd5af7..5abefc144e 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -240,7 +240,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
- strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>";
+ strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>";
+ strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 5b16b108e6..97b77cc93d 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -260,11 +260,10 @@ bool TransactionRecord::statusUpdateNeeded()
QString TransactionRecord::getTxID() const
{
- return formatSubTxId(hash, idx);
+ return QString::fromStdString(hash.ToString());
}
-QString TransactionRecord::formatSubTxId(const uint256 &hash, int vout)
+int TransactionRecord::getOutputIndex() const
{
- return QString::fromStdString(hash.ToString() + strprintf("-%03d", vout));
+ return idx;
}
-
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 49753ee31f..95ab98c10d 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -128,8 +128,8 @@ public:
/** Return the unique identifier for this transaction (part) */
QString getTxID() const;
- /** Format subtransaction id */
- static QString formatSubTxId(const uint256 &hash, int vout);
+ /** Return the output index of the subtransaction */
+ int getOutputIndex() const;
/** Update status from core wallet tx.
*/
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 45fb6c1642..89420b93d7 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -29,6 +29,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getaddednodeinfo", 0 },
{ "generate", 0 },
{ "generate", 1 },
+ { "generatetoaddress", 0 },
+ { "generatetoaddress", 1 },
+ { "generatetoaddress", 2 },
{ "getnetworkhashps", 0 },
{ "getnetworkhashps", 1 },
{ "sendtoaddress", 1 },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index c33082fca0..a2abbb323d 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "base58.h"
#include "amount.h"
#include "chain.h"
#include "chainparams.h"
@@ -93,42 +94,12 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp)
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
-UniValue generate(const UniValue& params, bool fHelp)
+UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "generate numblocks ( maxtries )\n"
- "\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
- "\nArguments:\n"
- "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
- "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
- "\nResult\n"
- "[ blockhashes ] (array) hashes of blocks generated\n"
- "\nExamples:\n"
- "\nGenerate 11 blocks\n"
- + HelpExampleCli("generate", "11")
- );
-
static const int nInnerLoopCount = 0x10000;
int nHeightStart = 0;
int nHeightEnd = 0;
int nHeight = 0;
- int nGenerate = params[0].get_int();
- uint64_t nMaxTries = 1000000;
- if (params.size() > 1) {
- nMaxTries = params[1].get_int();
- }
-
- boost::shared_ptr<CReserveScript> coinbaseScript;
- GetMainSignals().ScriptForMining(coinbaseScript);
-
- // If the keypool is exhausted, no script is returned at all. Catch this.
- if (!coinbaseScript)
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
-
- //throw an error if no script was provided
- if (coinbaseScript->reserveScript.empty())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
{ // Don't keep cs_main locked
LOCK(cs_main);
@@ -164,12 +135,84 @@ UniValue generate(const UniValue& params, bool fHelp)
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
- //mark script as important because it was used at least for one coinbase output
- coinbaseScript->KeepScript();
+ //mark script as important because it was used at least for one coinbase output if the script came from the wallet
+ if (keepScript)
+ {
+ coinbaseScript->KeepScript();
+ }
}
return blockHashes;
}
+UniValue generate(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "generate numblocks ( maxtries )\n"
+ "\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
+ "\nArguments:\n"
+ "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
+ "\nResult\n"
+ "[ blockhashes ] (array) hashes of blocks generated\n"
+ "\nExamples:\n"
+ "\nGenerate 11 blocks\n"
+ + HelpExampleCli("generate", "11")
+ );
+
+ int nGenerate = params[0].get_int();
+ uint64_t nMaxTries = 1000000;
+ if (params.size() > 1) {
+ nMaxTries = params[1].get_int();
+ }
+
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
+
+ // If the keypool is exhausted, no script is returned at all. Catch this.
+ if (!coinbaseScript)
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+
+ //throw an error if no script was provided
+ if (coinbaseScript->reserveScript.empty())
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
+
+ return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
+}
+
+UniValue generatetoaddress(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ throw runtime_error(
+ "generatetoaddress numblocks address (maxtries)\n"
+ "\nMine blocks immediately to a specified address (before the RPC call returns)\n"
+ "\nArguments:\n"
+ "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. address (string, required) The address to send the newly generated bitcoin to.\n"
+ "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
+ "\nResult\n"
+ "[ blockhashes ] (array) hashes of blocks generated\n"
+ "\nExamples:\n"
+ "\nGenerate 11 blocks to myaddress\n"
+ + HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
+ );
+
+ int nGenerate = params[0].get_int();
+ uint64_t nMaxTries = 1000000;
+ if (params.size() > 2) {
+ nMaxTries = params[2].get_int();
+ }
+
+ CBitcoinAddress address(params[1].get_str());
+ if (!address.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
+
+ boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
+ coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
+
+ return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
+}
+
UniValue getmininginfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index de89fdeb0f..34dd3b30f5 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -303,7 +303,8 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
UniValue res(UniValue::VARR);
vector<uint256> vMatch;
- if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
+ vector<unsigned int> vIndex;
+ if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
return res;
LOCK(cs_main);
@@ -818,11 +819,12 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
const CCoins* existingCoins = view.AccessCoins(hashTx);
bool fHaveMempool = mempool.exists(hashTx);
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
+ CFeeRate txFeeRate = CFeeRate(0);
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -835,7 +837,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx);
+ RelayTransaction(tx, txFeeRate);
return hashTx.GetHex();
}
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 33fa1437e2..1303a3bb13 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -299,6 +299,7 @@ static const CRPCCommand vRPCCommands[] =
/* Coin generation */
{ "generating", "generate", &generate, true },
+ { "generating", "generatetoaddress", &generatetoaddress, true },
/* Raw transactions */
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true },
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 38cb32e7f2..35e114feef 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -193,6 +193,7 @@ extern UniValue listbanned(const UniValue& params, bool fHelp);
extern UniValue clearbanned(const UniValue& params, bool fHelp);
extern UniValue generate(const UniValue& params, bool fHelp);
+extern UniValue generatetoaddress(const UniValue& params, bool fHelp);
extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
extern UniValue getmininginfo(const UniValue& params, bool fHelp);
extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 87d35be412..70f1f12273 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -4,193 +4,16 @@
// Unit tests for alert system
-#include "alert.h"
-#include "chain.h"
#include "chainparams.h"
-#include "clientversion.h"
-#include "data/alertTests.raw.h"
#include "main.h" // For PartitionCheck
-#include "serialize.h"
-#include "streams.h"
-#include "utilstrencodings.h"
#include "test/testutil.h"
#include "test/test_bitcoin.h"
-#include <fstream>
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#if 0
-//
-// alertTests contains 7 alerts, generated with this code:
-// (SignAndSave code not shown, alert signing key is secret)
-//
-{
- CAlert alert;
- alert.nRelayUntil = 60;
- alert.nExpiration = 24 * 60 * 60;
- alert.nID = 1;
- alert.nCancel = 0; // cancels previous messages up to this ID number
- alert.nMinVer = 0; // These versions are protocol versions
- alert.nMaxVer = 999001;
- alert.nPriority = 1;
- alert.strComment = "Alert comment";
- alert.strStatusBar = "Alert 1";
-
- SignAndSave(alert, "test/alertTests");
-
- alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
- alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
- SignAndSave(alert, "test/alertTests");
-
- alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
- alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
- SignAndSave(alert, "test/alertTests");
-
- alert.setSubVer.clear();
- ++alert.nID;
- alert.nCancel = 1;
- alert.nPriority = 100;
- alert.strStatusBar = "Alert 2, cancels 1";
- SignAndSave(alert, "test/alertTests");
-
- alert.nExpiration += 60;
- ++alert.nID;
- SignAndSave(alert, "test/alertTests");
-
- ++alert.nID;
- alert.nMinVer = 11;
- alert.nMaxVer = 22;
- SignAndSave(alert, "test/alertTests");
-
- ++alert.nID;
- alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
- alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
- SignAndSave(alert, "test/alertTests");
-
- ++alert.nID;
- alert.nMinVer = 0;
- alert.nMaxVer = 999999;
- alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
- alert.setSubVer.clear();
- SignAndSave(alert, "test/alertTests");
-}
-#endif
-
-struct ReadAlerts : public TestingSetup
-{
- ReadAlerts()
- {
- std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
- CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
- try {
- while (!stream.eof())
- {
- CAlert alert;
- stream >> alert;
- alerts.push_back(alert);
- }
- }
- catch (const std::exception&) { }
- }
- ~ReadAlerts() { }
-
- static std::vector<std::string> read_lines(boost::filesystem::path filepath)
- {
- std::vector<std::string> result;
-
- std::ifstream f(filepath.string().c_str());
- std::string line;
- while (std::getline(f,line))
- result.push_back(line);
-
- return result;
- }
-
- std::vector<CAlert> alerts;
-};
-
-BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
-
-
-BOOST_AUTO_TEST_CASE(AlertApplies)
-{
- SetMockTime(11);
- const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
+BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup)
- BOOST_FOREACH(const CAlert& alert, alerts)
- {
- BOOST_CHECK(alert.CheckSignature(alertKey));
- }
-
- BOOST_CHECK(alerts.size() >= 3);
-
- // Matches:
- BOOST_CHECK(alerts[0].AppliesTo(1, ""));
- BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
- BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));
-
- BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
- BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));
-
- BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
- BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));
-
- // Don't match:
- BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
- BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));
-
- BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
- BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
- BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
- BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));
-
- BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));
-
- SetMockTime(0);
-}
-
-
-BOOST_AUTO_TEST_CASE(AlertNotify)
-{
- SetMockTime(11);
- const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
-
- boost::filesystem::path temp = GetTempPath() /
- boost::filesystem::unique_path("alertnotify-%%%%.txt");
-
- mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
-
- BOOST_FOREACH(CAlert alert, alerts)
- alert.ProcessAlert(alertKey, false);
-
- std::vector<std::string> r = read_lines(temp);
- BOOST_CHECK_EQUAL(r.size(), 4u);
-
-// Windows built-in echo semantics are different than posixy shells. Quotes and
-// whitespace are printed literally.
-
-#ifndef WIN32
- BOOST_CHECK_EQUAL(r[0], "Alert 1");
- BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1");
- BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1");
- BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
-#else
- BOOST_CHECK_EQUAL(r[0], "'Alert 1' ");
- BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' ");
- BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' ");
- BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' ");
-#endif
- boost::filesystem::remove(temp);
-
- SetMockTime(0);
-}
static bool falseFunc() { return false; }
@@ -253,4 +76,4 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
SetMockTime(0);
}
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
new file mode 100644
index 0000000000..59dab20633
--- /dev/null
+++ b/src/test/amount_tests.cpp
@@ -0,0 +1,42 @@
+// 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.
+
+#include "amount.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(GetFeeTest)
+{
+ CFeeRate feeRate;
+
+ feeRate = CFeeRate(0);
+ // Must always return 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0);
+
+ feeRate = CFeeRate(1000);
+ // Must always just return the arg
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), 121);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), 999);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3);
+
+ feeRate = CFeeRate(123);
+ // Truncates the result, if not integer
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(8), 1); // Special case: returns 1 instead of 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9), 1);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), 14);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(122), 15);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bctest.py b/src/test/bctest.py
index 3a8d0ea51b..8105b87ffa 100644
--- a/src/test/bctest.py
+++ b/src/test/bctest.py
@@ -1,7 +1,7 @@
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
+from __future__ import division,print_function,unicode_literals
import subprocess
import os
import json
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
index 20afb16a9e..95dd3e81b4 100755
--- a/src/test/bitcoin-util-test.py
+++ b/src/test/bitcoin-util-test.py
@@ -2,7 +2,7 @@
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
+from __future__ import division,print_function,unicode_literals
import os
import bctest
import buildenv
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 98f9de7673..9557000ddc 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -204,7 +204,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -221,7 +222,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -249,7 +250,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -275,7 +277,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -303,7 +305,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -326,7 +329,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -353,7 +356,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -392,7 +396,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6);
vector<uint256> vMatched;
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ vector<unsigned int> vIndex;
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
@@ -409,7 +414,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
- BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
+ BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw
deleted file mode 100644
index 01f50680b9..0000000000
--- a/src/test/data/alertTests.raw
+++ /dev/null
Binary files differ
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 113b9437e0..2f3f607889 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -88,7 +88,8 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
// extract merkle root and matched txids from copy
std::vector<uint256> vMatchTxid2;
- uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2);
+ std::vector<unsigned int> vIndex;
+ uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex);
// check that it has the same merkle root as the original, and a valid one
BOOST_CHECK(merkleRoot1 == merkleRoot2);
@@ -102,7 +103,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
CPartialMerkleTreeTester pmt3(pmt2);
pmt3.Damage();
std::vector<uint256> vMatchTxid3;
- uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3);
+ uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex);
BOOST_CHECK(merkleRoot3 != merkleRoot1);
}
}
@@ -122,7 +123,8 @@ BOOST_AUTO_TEST_CASE(pmt_malleability)
CPartialMerkleTree tree(vTxid, vMatch);
std::vector<uint256> vTxid2;
- BOOST_CHECK(tree.ExtractMatches(vTxid).IsNull());
+ std::vector<unsigned int> vIndex;
+ BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index c29e30792a..237b26329b 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 4d2f8d1e3b..b6bcf86fbf 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -83,7 +83,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
int64_t nMedian = vTimeOffsets.median();
std::vector<int64_t> vSorted = vTimeOffsets.sorted();
// Only let other nodes change our time by so much
- if (abs64(nMedian) < 70 * 60)
+ if (abs64(nMedian) <= std::max<int64_t>(0, GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT)))
{
nTimeOffset = nMedian;
}
diff --git a/src/timedata.h b/src/timedata.h
index 2296baf11b..9f2499c85c 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -10,6 +10,8 @@
#include <stdint.h>
#include <vector>
+static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60;
+
class CNetAddr;
/**
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 088e5edde5..52c7793118 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -771,6 +771,16 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
return true;
}
+bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
+{
+ LOCK(cs);
+ indexed_transaction_set::const_iterator i = mapTx.find(hash);
+ if (i == mapTx.end())
+ return false;
+ feeRate = CFeeRate(i->GetFee(), i->GetTxSize());
+ return true;
+}
+
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
{
LOCK(cs);
diff --git a/src/txmempool.h b/src/txmempool.h
index 665bb44cf3..9dbb37dad0 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -600,6 +600,7 @@ public:
}
bool lookup(uint256 hash, CTransaction& result) const;
+ bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
/** Estimate fee rate needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 967d243270..0b51d52e65 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -83,10 +83,9 @@ public:
boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;
/**
- * New, updated or cancelled alert.
- * @note called with lock cs_mapAlerts held.
+ * Status bar alerts changed.
*/
- boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged;
+ boost::signals2::signal<void ()> NotifyAlertChanged;
/** A wallet has been loaded. */
boost::signals2::signal<void (CWallet* wallet)> LoadWallet;
diff --git a/src/uint256.h b/src/uint256.h
index 4495000f2f..bcdb6dd7c2 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -42,9 +42,11 @@ public:
memset(data, 0, sizeof(data));
}
- friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; }
- friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; }
- friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; }
+ inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); }
+
+ friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
+ friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
+ friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }
std::string GetHex() const;
void SetHex(const char* psz);
diff --git a/src/version.h b/src/version.h
index af2eb8eab6..0e1d8a63ce 100644
--- a/src/version.h
+++ b/src/version.h
@@ -9,7 +9,7 @@
* network protocol versioning
*/
-static const int PROTOCOL_VERSION = 70012;
+static const int PROTOCOL_VERSION = 70013;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@@ -36,4 +36,7 @@ static const int NO_BLOOM_VERSION = 70011;
//! "sendheaders" command and announcing blocks with headers starts with this version
static const int SENDHEADERS_VERSION = 70012;
+//! "feefilter" tells peers to filter invs to you by fee starts with this version
+static const int FEEFILTER_VERSION = 70013;
+
#endif // BITCOIN_VERSION_H
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 9ec28e7b91..bb40cf7245 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -13,6 +13,8 @@
#include "util.h"
#include "utiltime.h"
#include "wallet.h"
+#include "merkleblock.h"
+#include "core_io.h"
#include <fstream>
#include <stdint.h>
@@ -192,7 +194,7 @@ UniValue importaddress(const UniValue& params, bool fHelp)
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
- "If you have the full public key, you should call importpublickey instead of this.\n"
+ "If you have the full public key, you should call importpubkey instead of this.\n"
"\nExamples:\n"
"\nImport a script with rescan\n"
+ HelpExampleCli("importaddress", "\"myscript\"") +
@@ -243,6 +245,109 @@ UniValue importaddress(const UniValue& params, bool fHelp)
return NullUniValue;
}
+UniValue importprunedfunds(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ throw runtime_error(
+ "importprunedfunds\n"
+ "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
+ "\nArguments:\n"
+ "1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n"
+ "2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
+ "3. \"label\" (string, optional) An optional label\n"
+ );
+
+ CTransaction tx;
+ if (!DecodeHexTx(tx, params[0].get_str()))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+ uint256 hashTx = tx.GetHash();
+ CWalletTx wtx(pwalletMain,tx);
+
+ CDataStream ssMB(ParseHexV(params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
+ CMerkleBlock merkleBlock;
+ ssMB >> merkleBlock;
+
+ string strLabel = "";
+ if (params.size() == 3)
+ strLabel = params[2].get_str();
+
+ //Search partial merkle tree in proof for our transaction and index in valid block
+ vector<uint256> vMatch;
+ vector<unsigned int> vIndex;
+ unsigned int txnIndex = 0;
+ if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
+
+ LOCK(cs_main);
+
+ if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
+
+ vector<uint256>::const_iterator it;
+ if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
+ }
+
+ txnIndex = vIndex[it - vMatch.begin()];
+ }
+ else {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
+ }
+
+ wtx.nIndex = txnIndex;
+ wtx.hashBlock = merkleBlock.header.GetHash();
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ if (pwalletMain->IsMine(tx)) {
+ CWalletDB walletdb(pwalletMain->strWalletFile, "r+", false);
+ pwalletMain->AddToWallet(wtx, false, &walletdb);
+ return NullUniValue;
+ }
+
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
+}
+
+UniValue removeprunedfunds(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "removeprunedfunds \"txid\"\n"
+ "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n"
+ "\nArguments:\n"
+ "1. \"txid\" (string, required) The hex-encoded id of the transaction you are deleting\n"
+ "\nExamples:\n"
+ + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
+ );
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+ vector<uint256> vHash;
+ vHash.push_back(hash);
+ vector<uint256> vHashOut;
+
+ if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction.");
+ }
+
+ if(vHashOut.empty()) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet.");
+ }
+
+ ThreadFlushWalletDB(pwalletMain->strWalletFile);
+
+ return NullUniValue;
+}
+
UniValue importpubkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 759f894ccb..a1733bae77 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1346,6 +1346,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
if (fLong)
WalletTxToJSON(wtx, entry);
+ entry.push_back(Pair("abandoned", wtx.isAbandoned()));
ret.push_back(entry);
}
}
@@ -1438,6 +1439,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" \"vout\": n, (numeric) the vout value\n"
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
" 'send' category of transactions.\n"
+ " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable).\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
" 'receive' category of transactions. Negative confirmations indicate the\n"
" transaction conflicts with the block chain\n"
@@ -2098,16 +2100,17 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
+ "lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n"
"\nUpdates list of temporarily unspendable outputs.\n"
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
+ "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
"is always cleared (by virtue of process exit) when a node stops or fails.\n"
"Also see the listunspent call\n"
"\nArguments:\n"
"1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
- "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
+ "2. \"transactions\" (string, optional) A json array of objects. Each object the txid (string) vout (numeric)\n"
" [ (json array of json objects)\n"
" {\n"
" \"txid\":\"id\", (string) The transaction id\n"
@@ -2503,6 +2506,8 @@ extern UniValue importaddress(const UniValue& params, bool fHelp);
extern UniValue importpubkey(const UniValue& params, bool fHelp);
extern UniValue dumpwallet(const UniValue& params, bool fHelp);
extern UniValue importwallet(const UniValue& params, bool fHelp);
+extern UniValue importprunedfunds(const UniValue& params, bool fHelp);
+extern UniValue removeprunedfunds(const UniValue& params, bool fHelp);
const CRPCCommand vWalletRPCCommands[] =
{ // category name actor (function) okSafeMode
@@ -2529,6 +2534,7 @@ const CRPCCommand vWalletRPCCommands[] =
{ "wallet", "importprivkey", &importprivkey, true },
{ "wallet", "importwallet", &importwallet, true },
{ "wallet", "importaddress", &importaddress, true },
+ { "wallet", "importprunedfunds", &importprunedfunds, true },
{ "wallet", "importpubkey", &importpubkey, true },
{ "wallet", "keypoolrefill", &keypoolrefill, true },
{ "wallet", "listaccounts", &listaccounts, false },
@@ -2550,6 +2556,7 @@ const CRPCCommand vWalletRPCCommands[] =
{ "wallet", "walletlock", &walletlock, true },
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
{ "wallet", "walletpassphrase", &walletpassphrase, true },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, true },
};
void walletRegisterRPCCommands()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 1ef055e552..1ea8d2ffe7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1268,7 +1268,9 @@ bool CWalletTx::RelayWalletTransaction()
{
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
- RelayTransaction((CTransaction)*this);
+ CFeeRate feeRate;
+ mempool.lookupFeeRate(GetHash(), feeRate);
+ RelayTransaction((CTransaction)*this, feeRate);
return true;
}
}
@@ -1578,7 +1580,7 @@ CAmount CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -1623,7 +1625,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
@@ -1668,11 +1670,16 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth < 0)
continue;
+ // We should not consider coins which aren't at least in our mempool
+ // It's possible for these to be conflicted via ancestors which we may never be able to detect
+ if (nDepth == 0 && !pcoin->InMempool())
+ continue;
+
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
isminetype mine = IsMine(pcoin->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
- (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i)))
+ (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i))))
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
(coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO)));
@@ -1839,10 +1846,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
return true;
}
-bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
+bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
{
- vector<COutput> vCoins;
- AvailableCoins(vCoins, true, coinControl);
+ vector<COutput> vCoins(vAvailableCoins);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
@@ -1930,16 +1936,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC
// Add new txins (keeping original txin scriptSig/order)
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
- bool found = false;
- BOOST_FOREACH(const CTxIn& origTxIn, tx.vin)
- {
- if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n)
- {
- found = true;
- break;
- }
- }
- if (!found)
+ if (!coinControl.IsSelected(txin.prevout))
tx.vin.push_back(txin);
}
@@ -2008,6 +2005,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
{
LOCK2(cs_main, cs_wallet);
{
+ std::vector<COutput> vAvailableCoins;
+ AvailableCoins(vAvailableCoins, true, coinControl);
+
nFeeRet = 0;
// Start with no fee and loop until there is enough fee
while (true)
@@ -2057,7 +2057,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > setCoins;
CAmount nValueIn = 0;
- if (!SelectCoins(nValueToSelect, setCoins, nValueIn, coinControl))
+ if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
{
strFailReason = _("Insufficient funds");
return false;
@@ -2353,6 +2353,31 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
return DB_LOAD_OK;
}
+DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOut)
+{
+ if (!fFileBacked)
+ return DB_LOAD_OK;
+ DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(this, vHashIn, vHashOut);
+ if (nZapSelectTxRet == DB_NEED_REWRITE)
+ {
+ if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ {
+ LOCK(cs_wallet);
+ setKeyPool.clear();
+ // Note: can't top-up keypool here, because wallet is locked.
+ // User will be prompted to unlock wallet the next operation
+ // that requires a new key.
+ }
+ }
+
+ if (nZapSelectTxRet != DB_LOAD_OK)
+ return nZapSelectTxRet;
+
+ MarkDirty();
+
+ return DB_LOAD_OK;
+
+}
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
@@ -3231,5 +3256,5 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index d009211a92..5db36f52d1 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -544,7 +544,7 @@ private:
* all coins from coinControl are selected; Never select unconfirmed coins
* if they are not ours
*/
- bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
+ bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
CWalletDB *pwalletdbEncryption;
@@ -792,6 +792,7 @@ public:
DBErrors LoadWallet(bool& fFirstRunRet);
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 0a4a1dae2f..f2b5408e92 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -785,6 +785,45 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vec
return result;
}
+DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, vector<uint256>& vTxHashOut)
+{
+ // build list of wallet TXs and hashes
+ vector<uint256> vTxHash;
+ vector<CWalletTx> vWtx;
+ DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
+ if (err != DB_LOAD_OK) {
+ return err;
+ }
+
+ std::sort(vTxHash.begin(), vTxHash.end());
+ std::sort(vTxHashIn.begin(), vTxHashIn.end());
+
+ // erase each matching wallet TX
+ bool delerror = false;
+ vector<uint256>::iterator it = vTxHashIn.begin();
+ BOOST_FOREACH (uint256 hash, vTxHash) {
+ while (it < vTxHashIn.end() && (*it) < hash) {
+ it++;
+ }
+ if (it == vTxHashIn.end()) {
+ break;
+ }
+ else if ((*it) == hash) {
+ pwallet->mapWallet.erase(hash);
+ if(!EraseTx(hash)) {
+ LogPrint("db", "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
+ delerror = true;
+ }
+ vTxHashOut.push_back(hash);
+ }
+ }
+
+ if (delerror) {
+ return DB_CORRUPT;
+ }
+ return DB_LOAD_OK;
+}
+
DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 7e8cc4084e..fe6c366343 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -130,6 +130,7 @@ public:
DBErrors LoadWallet(CWallet* pwallet);
DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
+ DBErrors ZapSelectTx(CWallet* pwallet, std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
static bool Recover(CDBEnv& dbenv, const std::string& filename);