aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/debian/changelog30
-rw-r--r--contrib/debian/control7
-rw-r--r--contrib/devtools/README.md26
-rwxr-xr-xcontrib/devtools/clang-format.py62
-rwxr-xr-xcontrib/devtools/security-check.py181
-rwxr-xr-xcontrib/devtools/symbol-check.py30
-rwxr-xr-xcontrib/devtools/test-security-check.py60
-rwxr-xr-xdepends/config.guess14
-rwxr-xr-xdepends/config.sub11
-rwxr-xr-xqa/pull-tester/rpc-tests.py6
-rwxr-xr-xqa/rpc-tests/bip65-cltv-p2p.py175
-rwxr-xr-xqa/rpc-tests/bip65-cltv.py89
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py10
-rwxr-xr-xqa/rpc-tests/httpbasics.py14
-rwxr-xr-xqa/rpc-tests/pruning.py5
-rw-r--r--src/amount.h1
-rw-r--r--src/bitcoin-cli.cpp12
-rw-r--r--src/bitcoin-tx.cpp11
-rw-r--r--src/bitcoind.cpp8
-rw-r--r--src/chainparams.cpp33
-rw-r--r--src/chainparams.h15
-rw-r--r--src/chainparamsbase.cpp47
-rw-r--r--src/chainparamsbase.h31
-rw-r--r--src/compat.h1
-rw-r--r--src/consensus/params.h1
-rw-r--r--src/httpserver.cpp4
-rw-r--r--src/init.cpp13
-rw-r--r--src/main.cpp83
-rw-r--r--src/main.h6
-rw-r--r--src/net.cpp12
-rw-r--r--src/netbase.cpp9
-rw-r--r--src/pow.cpp3
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/rpcblockchain.cpp1
-rw-r--r--src/rpcclient.cpp1
-rw-r--r--src/rpcrawtransaction.cpp22
-rw-r--r--src/script/bitcoinconsensus.h7
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script.h9
-rw-r--r--src/test/data/tx_invalid.json4
-rw-r--r--src/test/data/tx_valid.json4
-rw-r--r--src/test/mempool_tests.cpp199
-rw-r--r--src/test/test_bitcoin.cpp6
-rw-r--r--src/test/test_bitcoin.h4
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/txmempool.cpp92
-rw-r--r--src/txmempool.h48
-rw-r--r--src/wallet/wallet.cpp2
50 files changed, 1238 insertions, 191 deletions
diff --git a/contrib/debian/changelog b/contrib/debian/changelog
index bd7ab3524c..110bfe03ef 100644
--- a/contrib/debian/changelog
+++ b/contrib/debian/changelog
@@ -1,3 +1,33 @@
+bitcoin (0.11.0-precise1) precise; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 14 Jul 2015 14:39:00 -1000
+
+bitcoin (0.10.2-precise1) precise; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 29 Jun 2015 17:33:00 -1000
+
+bitcoin (0.10.1-precise3) precise; urgency=medium
+
+ * Fix build dep (include python).
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 5 May 2015 09:28:00 -1000
+
+bitcoin (0.10.1-precise2) precise; urgency=medium
+
+ * Fix miniupnpc dep.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 5 May 2015 00:33:00 -1000
+
+bitcoin (0.10.1-precise1) precise; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 5 May 2015 00:07:00 -1000
+
bitcoin (0.10.0-precise1) precise; urgency=medium
* New upstream releases.
diff --git a/contrib/debian/control b/contrib/debian/control
index 01625b8438..2fd68583ce 100644
--- a/contrib/debian/control
+++ b/contrib/debian/control
@@ -20,11 +20,12 @@ Build-Depends: debhelper,
qt4-qmake,
libqt4-dev,
libqrencode-dev,
- libprotobuf-dev, protobuf-compiler
+ libprotobuf-dev, protobuf-compiler,
+ python
Standards-Version: 3.9.2
-Homepage: http://www.bitcoin.org/
+Homepage: https://www.bitcoin.org/
Vcs-Git: git://github.com/bitcoin/bitcoin.git
-Vcs-Browser: http://github.com/bitcoin/bitcoin
+Vcs-Browser: https://github.com/bitcoin/bitcoin
Package: bitcoind
Architecture: any
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index f90afa7f20..278794f14c 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -1,9 +1,14 @@
Contents
-===========
+========
This directory contains tools for developers working on this repository.
+clang-format.py
+===============
+
+A script to format cpp source code according to [.clang-format](../../src/.clang-format). This should only be applied to new files or files which are currently not actively developed on. Also, git subtrees are not subject to formatting.
+
github-merge.sh
-==================
+===============
A small script to automate merging pull-requests securely and sign them with GPG.
@@ -37,23 +42,31 @@ Configuring the github-merge tool for the bitcoin repository is done in the foll
git config --global user.signingkey mykeyid (if you want to GPG sign)
fix-copyright-headers.py
-===========================
+========================
Every year newly updated files need to have its copyright headers updated to reflect the current year.
If you run this script from src/ it will automatically update the year on the copyright header for all
.cpp and .h files if these have a git commit from the current year.
For example a file changed in 2014 (with 2014 being the current year):
+
```// Copyright (c) 2009-2013 The Bitcoin Core developers```
would be changed to:
+
```// Copyright (c) 2009-2014 The Bitcoin Core developers```
+optimize-pngs.py
+================
+
+A script to optimize png files in the bitcoin
+repository (requires pngcrush).
+
symbol-check.py
-==================
+===============
A script to check that the (Linux) executables produced by gitian only contain
-allowed gcc, glibc and libstdc++ version symbols. This makes sure they are
+allowed gcc, glibc and libstdc++ version symbols. This makes sure they are
still compatible with the minimum supported Linux distribution versions.
Example usage after a gitian build:
@@ -70,7 +83,7 @@ If there are 'unsupported' symbols, the return value will be 1 a list like this
.../64/test_bitcoin: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15
update-translations.py
-=======================
+======================
Run this script from the root of the repository to update all translations from transifex.
It will do the following automatically:
@@ -93,4 +106,5 @@ maintained:
* for sec/leveldb: https://github.com/bitcoin/leveldb.git (branch bitcoin-fork)
Usage: git-subtree-check.sh DIR COMMIT
+
COMMIT may be omitted, in which case HEAD is used.
diff --git a/contrib/devtools/clang-format.py b/contrib/devtools/clang-format.py
new file mode 100755
index 0000000000..cee99047ac
--- /dev/null
+++ b/contrib/devtools/clang-format.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+'''
+Wrapper script for clang-format
+
+Copyright (c) 2015 MarcoFalke
+Copyright (c) 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.
+'''
+
+import os
+import sys
+import subprocess
+
+tested_versions = ['3.6.0', '3.6.1', '3.6.2'] # A set of versions known to produce the same output
+accepted_file_extensions = ('.h', '.cpp') # Files to format
+
+def check_clang_format_version(clang_format_exe):
+ try:
+ output = subprocess.check_output([clang_format_exe, '-version'])
+ for ver in tested_versions:
+ if ver in output:
+ print "Detected clang-format version " + ver
+ return
+ raise RuntimeError("Untested version: " + output)
+ except Exception as e:
+ print 'Could not verify version of ' + clang_format_exe + '.'
+ raise e
+
+def check_command_line_args(argv):
+ required_args = ['{clang-format-exe}', '{files}']
+ example_args = ['clang-format-3.x', 'src/main.cpp', 'src/wallet/*']
+
+ if(len(argv) < len(required_args) + 1):
+ for word in (['Usage:', argv[0]] + required_args):
+ print word,
+ print ''
+ for word in (['E.g:', argv[0]] + example_args):
+ print word,
+ print ''
+ sys.exit(1)
+
+def run_clang_format(clang_format_exe, files):
+ for target in files:
+ if os.path.isdir(target):
+ for path, dirs, files in os.walk(target):
+ run_clang_format(clang_format_exe, (os.path.join(path, f) for f in files))
+ elif target.endswith(accepted_file_extensions):
+ print "Format " + target
+ subprocess.check_call([clang_format_exe, '-i', '-style=file', target], stdout=open(os.devnull, 'wb'), stderr=subprocess.STDOUT)
+ else:
+ print "Skip " + target
+
+def main(argv):
+ check_command_line_args(argv)
+ clang_format_exe = argv[1]
+ files = argv[2:]
+ check_clang_format_version(clang_format_exe)
+ run_clang_format(clang_format_exe, files)
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
new file mode 100755
index 0000000000..e96eaa9c38
--- /dev/null
+++ b/contrib/devtools/security-check.py
@@ -0,0 +1,181 @@
+#!/usr/bin/python2
+'''
+Perform basic ELF security checks on a series of executables.
+Exit status will be 0 if succesful, 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
+import subprocess
+import sys
+import os
+
+READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
+OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
+
+def check_ELF_PIE(executable):
+ '''
+ Check for position independent executable (PIE), allowing for address space randomization.
+ '''
+ p = subprocess.Popen([READELF_CMD, '-h', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.returncode:
+ raise IOError('Error opening file')
+
+ ok = False
+ for line in stdout.split('\n'):
+ line = line.split()
+ if len(line)>=2 and line[0] == 'Type:' and line[1] == 'DYN':
+ ok = True
+ return ok
+
+def get_ELF_program_headers(executable):
+ '''Return type and flags for ELF program headers'''
+ p = subprocess.Popen([READELF_CMD, '-l', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.returncode:
+ raise IOError('Error opening file')
+ in_headers = False
+ count = 0
+ headers = []
+ for line in stdout.split('\n'):
+ if line.startswith('Program Headers:'):
+ in_headers = True
+ if line == '':
+ 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')
+ 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:
+ typ = line[ofs_typ:ofs_offset].rstrip()
+ flags = line[ofs_flags:ofs_align].rstrip()
+ headers.append((typ, flags))
+ count += 1
+ return headers
+
+def check_ELF_NX(executable):
+ '''
+ Check that no sections are writable and executable (including the stack)
+ '''
+ have_wx = False
+ have_gnu_stack = False
+ for (typ, flags) in get_ELF_program_headers(executable):
+ if typ == 'GNU_STACK':
+ have_gnu_stack = True
+ if 'W' in flags and 'E' in flags: # section is both writable and executable
+ have_wx = True
+ return have_gnu_stack and not have_wx
+
+def check_ELF_RELRO(executable):
+ '''
+ Check for read-only relocations.
+ GNU_RELRO program header must exist
+ Dynamic section must have BIND_NOW flag
+ '''
+ have_gnu_relro = False
+ for (typ, flags) in get_ELF_program_headers(executable):
+ # Note: not checking flags == 'R': here as linkers set the permission differently
+ # This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions.
+ # 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':
+ have_gnu_relro = True
+
+ have_bindnow = False
+ p = subprocess.Popen([READELF_CMD, '-d', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.returncode:
+ raise IOError('Error opening file')
+ for line in stdout.split('\n'):
+ tokens = line.split()
+ if len(tokens)>1 and tokens[1] == '(BIND_NOW)':
+ have_bindnow = True
+ return have_gnu_relro and have_bindnow
+
+def check_ELF_Canary(executable):
+ '''
+ Check for use of stack canary
+ '''
+ p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.returncode:
+ raise IOError('Error opening file')
+ ok = False
+ for line in stdout.split('\n'):
+ if '__stack_chk_fail' in line:
+ ok = True
+ return ok
+
+def get_PE_dll_characteristics(executable):
+ '''
+ Get PE DllCharacteristics bits
+ '''
+ p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.returncode:
+ raise IOError('Error opening file')
+ for line in stdout.split('\n'):
+ tokens = line.split()
+ if len(tokens)>=2 and tokens[0] == 'DllCharacteristics':
+ return int(tokens[1],16)
+ return 0
+
+
+def check_PE_PIE(executable):
+ '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)'''
+ return bool(get_PE_dll_characteristics(executable) & 0x40)
+
+def check_PE_NX(executable):
+ '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''
+ return bool(get_PE_dll_characteristics(executable) & 0x100)
+
+CHECKS = {
+'ELF': [
+ ('PIE', check_ELF_PIE),
+ ('NX', check_ELF_NX),
+ ('RELRO', check_ELF_RELRO),
+ ('Canary', check_ELF_Canary)
+],
+'PE': [
+ ('PIE', check_PE_PIE),
+ ('NX', check_PE_NX)
+]
+}
+
+def identify_executable(executable):
+ with open(filename, 'rb') as f:
+ magic = f.read(4)
+ if magic.startswith(b'MZ'):
+ return 'PE'
+ elif magic.startswith(b'\x7fELF'):
+ return 'ELF'
+ return None
+
+if __name__ == '__main__':
+ retval = 0
+ for filename in sys.argv[1:]:
+ try:
+ etype = identify_executable(filename)
+ if etype is None:
+ print('%s: unknown format' % filename)
+ retval = 1
+ continue
+
+ failed = []
+ for (name, func) in CHECKS[etype]:
+ if not func(filename):
+ failed.append(name)
+ if failed:
+ print('%s: failed %s' % (filename, ' '.join(failed)))
+ retval = 1
+ except IOError:
+ print('%s: cannot open' % filename)
+ retval = 1
+ exit(retval)
+
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index fad891f800..34f1ed2d17 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python2
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,6 +15,7 @@ from __future__ import division, print_function
import subprocess
import re
import sys
+import os
# Debian 6.0.9 (Squeeze) has:
#
@@ -45,8 +46,10 @@ MAX_VERSIONS = {
IGNORE_EXPORTS = {
'_edata', '_end', '_init', '__bss_start', '_fini'
}
-READELF_CMD = '/usr/bin/readelf'
-CPPFILT_CMD = '/usr/bin/c++filt'
+READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
+CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
+# Allowed NEEDED libraries
+ALLOWED_LIBRARIES = {'librt.so.1','libpthread.so.0','libanl.so.1','libm.so.6','libgcc_s.so.1','libc.so.6','ld-linux-x86-64.so.2'}
class CPPFilt(object):
'''
@@ -98,6 +101,22 @@ def check_version(max_versions, version):
return False
return ver <= max_versions[lib]
+def read_libraries(filename):
+ p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.returncode:
+ raise IOError('Error opening file')
+ libraries = []
+ for line in stdout.split('\n'):
+ tokens = line.split()
+ if len(tokens)>2 and tokens[1] == '(NEEDED)':
+ match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
+ if match:
+ libraries.append(match.group(1))
+ else:
+ raise ValueError('Unparseable (NEEDED) specification')
+ return libraries
+
if __name__ == '__main__':
cppfilt = CPPFilt()
retval = 0
@@ -113,6 +132,11 @@ if __name__ == '__main__':
continue
print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))
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))
+ retval = 1
exit(retval)
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
new file mode 100755
index 0000000000..fed7626aab
--- /dev/null
+++ b/contrib/devtools/test-security-check.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python2
+'''
+Test script for security-check.py
+'''
+from __future__ import division,print_function
+import subprocess
+import sys
+import unittest
+
+def write_testcode(filename):
+ with open(filename, 'w') as f:
+ f.write('''
+ #include <stdio.h>
+ int main()
+ {
+ printf("the quick brown fox jumps over the lazy god\\n");
+ return 0;
+ }
+ ''')
+
+def call_security_check(cc, source, executable, options):
+ subprocess.check_call([cc,source,'-o',executable] + options)
+ p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ return (p.returncode, stdout.rstrip())
+
+class TestSecurityChecks(unittest.TestCase):
+ def test_ELF(self):
+ source = 'test1.c'
+ executable = 'test1'
+ cc = 'gcc'
+ write_testcode(source)
+
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']),
+ (1, executable+': failed PIE NX RELRO Canary'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']),
+ (1, executable+': failed PIE RELRO Canary'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']),
+ (1, executable+': failed PIE RELRO'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']),
+ (1, executable+': failed RELRO'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']),
+ (0, ''))
+
+ def test_PE(self):
+ source = 'test1.c'
+ executable = 'test1.exe'
+ cc = 'i686-w64-mingw32-gcc'
+ write_testcode(source)
+
+ self.assertEqual(call_security_check(cc, source, executable, []),
+ (1, executable+': failed PIE NX'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']),
+ (1, executable+': failed PIE'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']),
+ (0, ''))
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/depends/config.guess b/depends/config.guess
index f357ec6c8f..3c022c5bb8 100755
--- a/depends/config.guess
+++ b/depends/config.guess
@@ -2,7 +2,7 @@
# Attempt to guess a canonical system name.
# Copyright 1992-2015 Free Software Foundation, Inc.
-timestamp='2015-03-04'
+timestamp='2015-09-14'
# 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
@@ -221,7 +221,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu'
;;
*)
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@@ -249,6 +249,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;;
+ *:Sortix:*:*)
+ echo ${UNAME_MACHINE}-unknown-sortix
+ exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
@@ -962,6 +965,9 @@ EOF
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
+ k1om:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
@@ -1038,7 +1044,7 @@ EOF
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@@ -1117,7 +1123,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
- # prints for the "djgpp" host, or else GDB configure will decide that
+ # prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
diff --git a/depends/config.sub b/depends/config.sub
index 8f1229c6f7..1acc966a33 100755
--- a/depends/config.sub
+++ b/depends/config.sub
@@ -2,7 +2,7 @@
# Configuration validation subroutine script.
# Copyright 1992-2015 Free Software Foundation, Inc.
-timestamp='2015-03-08'
+timestamp='2015-08-20'
# 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
@@ -255,6 +255,7 @@ case $basic_machine in
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
+ | ba \
| be32 | be64 \
| bfin \
| c4x | c8051 | clipper \
@@ -305,7 +306,7 @@ case $basic_machine in
| riscv32 | riscv64 \
| rl78 | rx \
| score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -376,6 +377,7 @@ case $basic_machine in
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
+ | ba-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
@@ -428,12 +430,13 @@ case $basic_machine in
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
+ | riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
@@ -1376,7 +1379,7 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* | -cloudabi* \
+ | -aos* | -aros* | -cloudabi* | -sortix* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 65a021bbc2..7e682d530a 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -70,6 +70,8 @@ testScripts = [
'blockchain.py',
]
testScriptsExt = [
+ 'bip65-cltv.py',
+ 'bip65-cltv-p2p.py',
'bipdersig-p2p.py',
'bipdersig.py',
'getblocktemplate_longpoll.py',
@@ -101,7 +103,7 @@ if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
if (len(opts) == 0 or (len(opts) == 1 and "-win" in opts ) or '-extended' in opts
or testScripts[i] in opts or re.sub(".py$", "", testScripts[i]) in opts ):
print "Running testscript " + testScripts[i] + "..."
- subprocess.call(rpcTestDir + testScripts[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True)
+ subprocess.check_call(rpcTestDir + testScripts[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True)
#exit if help is called so we print just one set of instructions
p = re.compile(" -h| --help")
if p.match(passOn):
@@ -112,6 +114,6 @@ if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
if ('-extended' in opts or testScriptsExt[i] in opts
or re.sub(".py$", "", testScriptsExt[i]) in opts):
print "Running 2nd level testscript " + testScriptsExt[i] + "..."
- subprocess.call(rpcTestDir + testScriptsExt[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True)
+ subprocess.check_call(rpcTestDir + testScriptsExt[i] + " --srcdir " + buildDir + '/src ' + passOn,shell=True)
else:
print "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"
diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py
new file mode 100755
index 0000000000..1f8548c219
--- /dev/null
+++ b/qa/rpc-tests/bip65-cltv-p2p.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python2
+#
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+
+from test_framework.test_framework import ComparisonTestFramework
+from test_framework.util import *
+from test_framework.mininode import CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block
+from test_framework.comptool import TestInstance, TestManager
+from test_framework.script import CScript, OP_1NEGATE, OP_NOP2, OP_DROP
+from binascii import hexlify, unhexlify
+import cStringIO
+import time
+
+def cltv_invalidate(tx):
+ '''Modify the signature in vin 0 of the tx to fail CLTV
+
+ Prepends -1 CLTV DROP in the scriptSig itself.
+ '''
+ tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_NOP2, OP_DROP] +
+ list(CScript(tx.vin[0].scriptSig)))
+
+'''
+This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY)
+Connect to a single node.
+Mine 2 (version 3) blocks (save the coinbases for later).
+Generate 98 more version 3 blocks, verify the node accepts.
+Mine 749 version 4 blocks, verify the node accepts.
+Check that the new CLTV rules are not enforced on the 750th version 4 block.
+Check that the new CLTV rules are enforced on the 751st version 4 block.
+Mine 199 new version blocks.
+Mine 1 old-version block.
+Mine 1 new version block.
+Mine 1 old version block, see that the node rejects.
+'''
+
+class BIP65Test(ComparisonTestFramework):
+
+ def __init__(self):
+ self.num_nodes = 1
+
+ def setup_network(self):
+ # Must set the blockversion for this test
+ self.nodes = start_nodes(1, self.options.tmpdir,
+ extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']],
+ binary=[self.options.testbinary])
+
+ def run_test(self):
+ test = TestManager(self, self.options.tmpdir)
+ test.add_all_connections(self.nodes)
+ NetworkThread().start() # Start up network handling in another thread
+ test.run()
+
+ def create_transaction(self, node, coinbase, to_address, amount):
+ from_txid = node.getblock(coinbase)['tx'][0]
+ inputs = [{ "txid" : from_txid, "vout" : 0}]
+ outputs = { to_address : amount }
+ rawtx = node.createrawtransaction(inputs, outputs)
+ signresult = node.signrawtransaction(rawtx)
+ tx = CTransaction()
+ f = cStringIO.StringIO(unhexlify(signresult['hex']))
+ tx.deserialize(f)
+ return tx
+
+ def get_tests(self):
+
+ self.coinbase_blocks = self.nodes[0].generate(2)
+ self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
+ self.nodeaddress = self.nodes[0].getnewaddress()
+ self.last_block_time = time.time()
+
+ ''' 98 more version 3 blocks '''
+ test_blocks = []
+ for i in xrange(98):
+ block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
+ block.nVersion = 3
+ block.rehash()
+ block.solve()
+ test_blocks.append([block, True])
+ self.last_block_time += 1
+ self.tip = block.sha256
+ yield TestInstance(test_blocks, sync_every_block=False)
+
+ ''' Mine 749 version 4 blocks '''
+ test_blocks = []
+ for i in xrange(749):
+ block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
+ block.nVersion = 4
+ block.rehash()
+ block.solve()
+ test_blocks.append([block, True])
+ self.last_block_time += 1
+ self.tip = block.sha256
+ yield TestInstance(test_blocks, sync_every_block=False)
+
+ '''
+ Check that the new CLTV rules are not enforced in the 750th
+ version 3 block.
+ '''
+ spendtx = self.create_transaction(self.nodes[0],
+ self.coinbase_blocks[0], self.nodeaddress, 1.0)
+ cltv_invalidate(spendtx)
+ spendtx.rehash()
+
+ block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
+ block.nVersion = 4
+ block.vtx.append(spendtx)
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.rehash()
+ block.solve()
+
+ self.last_block_time += 1
+ self.tip = block.sha256
+ yield TestInstance([[block, True]])
+
+ '''
+ Check that the new CLTV rules are enforced in the 751st version 4
+ block.
+ '''
+ spendtx = self.create_transaction(self.nodes[0],
+ self.coinbase_blocks[1], self.nodeaddress, 1.0)
+ cltv_invalidate(spendtx)
+ spendtx.rehash()
+
+ block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
+ block.nVersion = 4
+ block.vtx.append(spendtx)
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.rehash()
+ block.solve()
+ self.last_block_time += 1
+ yield TestInstance([[block, False]])
+
+ ''' Mine 199 new version blocks on last valid tip '''
+ test_blocks = []
+ for i in xrange(199):
+ block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
+ block.nVersion = 4
+ block.rehash()
+ block.solve()
+ test_blocks.append([block, True])
+ self.last_block_time += 1
+ self.tip = block.sha256
+ yield TestInstance(test_blocks, sync_every_block=False)
+
+ ''' Mine 1 old version block '''
+ block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
+ block.nVersion = 3
+ block.rehash()
+ block.solve()
+ self.last_block_time += 1
+ self.tip = block.sha256
+ yield TestInstance([[block, True]])
+
+ ''' Mine 1 new version block '''
+ block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
+ block.nVersion = 4
+ block.rehash()
+ block.solve()
+ self.last_block_time += 1
+ self.tip = block.sha256
+ yield TestInstance([[block, True]])
+
+ ''' Mine 1 old version block, should be invalid '''
+ block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
+ block.nVersion = 3
+ block.rehash()
+ block.solve()
+ self.last_block_time += 1
+ yield TestInstance([[block, False]])
+
+if __name__ == '__main__':
+ BIP65Test().main()
diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py
new file mode 100755
index 0000000000..e90e11e6a7
--- /dev/null
+++ b/qa/rpc-tests/bip65-cltv.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python2
+# Copyright (c) 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.
+
+#
+# Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic
+#
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import os
+import shutil
+
+class BIP65Test(BitcoinTestFramework):
+
+ def setup_network(self):
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, []))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=3"]))
+ self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=4"]))
+ connect_nodes(self.nodes[1], 0)
+ connect_nodes(self.nodes[2], 0)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ cnt = self.nodes[0].getblockcount()
+
+ # Mine some old-version blocks
+ self.nodes[1].generate(100)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 100):
+ raise AssertionError("Failed to mine 100 version=3 blocks")
+
+ # Mine 750 new-version blocks
+ for i in xrange(15):
+ self.nodes[2].generate(50)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 850):
+ raise AssertionError("Failed to mine 750 version=4 blocks")
+
+ # TODO: check that new CHECKLOCKTIMEVERIFY rules are not enforced
+
+ # Mine 1 new-version block
+ self.nodes[2].generate(1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 851):
+ raise AssertionFailure("Failed to mine a version=4 blocks")
+
+ # TODO: check that new CHECKLOCKTIMEVERIFY rules are enforced
+
+ # Mine 198 new-version blocks
+ for i in xrange(2):
+ self.nodes[2].generate(99)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1049):
+ raise AssertionError("Failed to mine 198 version=4 blocks")
+
+ # Mine 1 old-version block
+ self.nodes[1].generate(1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1050):
+ raise AssertionError("Failed to mine a version=3 block after 949 version=4 blocks")
+
+ # Mine 1 new-version blocks
+ self.nodes[2].generate(1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1051):
+ raise AssertionError("Failed to mine a version=4 block")
+
+ # Mine 1 old-version blocks
+ try:
+ self.nodes[1].generate(1)
+ raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks")
+ except JSONRPCException:
+ pass
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1051):
+ raise AssertionError("Accepted a version=3 block after 950 version=4 blocks")
+
+ # Mine 1 new-version blocks
+ self.nodes[2].generate(1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1052):
+ raise AssertionError("Failed to mine a version=4 block")
+
+if __name__ == '__main__':
+ BIP65Test().main()
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index fc29789218..93d13faa06 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -28,7 +28,15 @@ class RawTransactionsTest(BitcoinTestFramework):
def run_test(self):
print "Mining blocks..."
- feeTolerance = Decimal(0.00000002) #if the fee's positive delta is higher than this value tests will fail, neg. delta always fail the tests
+
+ min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
+ # if the fee's positive delta is higher than this value tests will fail,
+ # neg. delta always fail the tests.
+ # The size of the signature of every input may be at most 2 bytes larger
+ # than a minimum sized signature.
+
+ # = 2 bytes * minRelayTxFeePerByte
+ feeTolerance = 2 * min_relay_tx_fee/1000
self.nodes[2].generate(1)
self.sync_all()
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index b66533543d..7888114c54 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -97,5 +97,19 @@ class HTTPBasicsTest (BitcoinTestFramework):
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
+ # Check excessive request size
+ conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port)
+ conn.connect()
+ conn.request('GET', '/' + ('x'*1000), '', headers)
+ out1 = conn.getresponse()
+ assert_equal(out1.status, httplib.NOT_FOUND)
+
+ conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port)
+ conn.connect()
+ conn.request('GET', '/' + ('x'*10000), '', headers)
+ out1 = conn.getresponse()
+ assert_equal(out1.status, httplib.BAD_REQUEST)
+
+
if __name__ == '__main__':
HTTPBasicsTest ().main ()
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index 2824c51ce7..21f8d69382 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -61,6 +61,9 @@ class PruneTest(BitcoinTestFramework):
self.address[0] = self.nodes[0].getnewaddress()
self.address[1] = self.nodes[1].getnewaddress()
+ # Determine default relay fee
+ self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
+
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 2)
connect_nodes(self.nodes[2], 0)
@@ -239,7 +242,7 @@ class PruneTest(BitcoinTestFramework):
outputs = {}
t = self.utxo.pop()
inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
- remchange = t["amount"] - Decimal("0.001000")
+ remchange = t["amount"] - 100*self.relayfee # Fee must be above min relay rate for 66kb tx
outputs[address]=remchange
# Create a basic transaction that will send change back to ourself after account for a fee
# And then insert the 128 generated transaction outs in the middle rawtx[92] is where the #
diff --git a/src/amount.h b/src/amount.h
index 90e6b5aa8e..a4c7764cda 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -51,6 +51,7 @@ public:
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; }
+ CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString() const;
ADD_SERIALIZE_METHODS;
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index e0fe6aa5bf..6f22c70494 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -31,9 +31,7 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf"));
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
- strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
- strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be "
- "solved instantly. This is intended for regression testing tools and app development."));
+ AppendParamsHelpMessages(strUsage);
strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1"));
strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 8332, 18332));
strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
@@ -69,7 +67,7 @@ static bool AppInitRPC(int argc, char* argv[])
// Parameters
//
ParseParameters(argc, argv);
- if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) {
+ if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
std::string strUsage = _("Bitcoin Core RPC client version") + " " + FormatFullVersion() + "\n";
if (!mapArgs.count("-version")) {
strUsage += "\n" + _("Usage:") + "\n" +
@@ -94,8 +92,10 @@ static bool AppInitRPC(int argc, char* argv[])
return false;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
- if (!SelectBaseParamsFromCommandLine()) {
- fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
+ try {
+ SelectBaseParams(ChainNameFromCommandLine());
+ } catch(std::exception &e) {
+ fprintf(stderr, "Error: %s\n", e.what());
return false;
}
if (GetBoolArg("-rpcssl", false))
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index f7518fab5d..3330fe5d12 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -35,14 +35,16 @@ static bool AppInitRawTx(int argc, char* argv[])
ParseParameters(argc, argv);
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
- if (!SelectParamsFromCommandLine()) {
- fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
+ try {
+ SelectParams(ChainNameFromCommandLine());
+ } catch(std::exception &e) {
+ fprintf(stderr, "Error: %s\n", e.what());
return false;
}
fCreateBlank = GetBoolArg("-create", false);
- if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help"))
+ if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
{
// First part of help message is specific to this utility
std::string strUsage = _("Bitcoin Core bitcoin-tx utility version") + " " + FormatFullVersion() + "\n\n" +
@@ -58,8 +60,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("-create", _("Create new, empty TX."));
strUsage += HelpMessageOpt("-json", _("Select JSON output"));
strUsage += HelpMessageOpt("-txid", _("Output only the hex-encoded transaction id of the resultant transaction."));
- strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly."));
- strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
+ AppendParamsHelpMessages(strUsage);
fprintf(stdout, "%s", strUsage.c_str());
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index b512f74c22..d2af897242 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -72,7 +72,7 @@ bool AppInit(int argc, char* argv[])
ParseParameters(argc, argv);
// Process help and version before taking care about datadir
- if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
+ if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version"))
{
std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n";
@@ -107,8 +107,10 @@ bool AppInit(int argc, char* argv[])
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
- if (!SelectParamsFromCommandLine()) {
- fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
+ try {
+ SelectParams(ChainNameFromCommandLine());
+ } catch(std::exception &e) {
+ fprintf(stderr, "Error: %s\n", e.what());
return false;
}
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 430b75683b..dd26c3b31a 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -5,6 +5,7 @@
#include "chainparams.h"
+#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -76,6 +77,7 @@ public:
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
+ consensus.fPowNoRetargeting = false;
/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
@@ -155,6 +157,7 @@ public:
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
+ consensus.fPowNoRetargeting = false;
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
@@ -217,6 +220,7 @@ public:
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
+ consensus.fPowNoRetargeting = true;
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
@@ -263,31 +267,20 @@ const CChainParams &Params() {
return *pCurrentParams;
}
-CChainParams &Params(CBaseChainParams::Network network) {
- switch (network) {
- case CBaseChainParams::MAIN:
+CChainParams& Params(const std::string& chain)
+{
+ if (chain == CBaseChainParams::MAIN)
return mainParams;
- case CBaseChainParams::TESTNET:
+ else if (chain == CBaseChainParams::TESTNET)
return testNetParams;
- case CBaseChainParams::REGTEST:
+ else if (chain == CBaseChainParams::REGTEST)
return regTestParams;
- default:
- assert(false && "Unimplemented network");
- return mainParams;
- }
+ else
+ throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
-void SelectParams(CBaseChainParams::Network network) {
+void SelectParams(const std::string& network)
+{
SelectBaseParams(network);
pCurrentParams = &Params(network);
}
-
-bool SelectParamsFromCommandLine()
-{
- CBaseChainParams::Network network = NetworkIdFromCommandLine();
- if (network == CBaseChainParams::MAX_NETWORK_TYPES)
- return false;
-
- SelectParams(network);
- return true;
-}
diff --git a/src/chainparams.h b/src/chainparams.h
index 342bccb12f..cb061d596e 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -105,16 +105,15 @@ protected:
*/
const CChainParams &Params();
-/** Return parameters for the given network. */
-CChainParams &Params(CBaseChainParams::Network network);
-
-/** Sets the params returned by Params() to those for the given network. */
-void SelectParams(CBaseChainParams::Network network);
+/**
+ * @returns CChainParams for the given BIP70 chain name.
+ */
+CChainParams& Params(const std::string& chain);
/**
- * Looks for -regtest or -testnet and then calls SelectParams as appropriate.
- * Returns false if an invalid combination is given.
+ * Sets the params returned by Params() to those for the given BIP70 chain name.
+ * @throws std::runtime_error when the chain is not supported.
*/
-bool SelectParamsFromCommandLine();
+void SelectParams(const std::string& chain);
#endif // BITCOIN_CHAINPARAMS_H
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 9c87bf2154..db2dc751f5 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -5,10 +5,25 @@
#include "chainparamsbase.h"
+#include "tinyformat.h"
#include "util.h"
#include <assert.h>
+const std::string CBaseChainParams::MAIN = "main";
+const std::string CBaseChainParams::TESTNET = "test";
+const std::string CBaseChainParams::REGTEST = "regtest";
+
+void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp)
+{
+ strUsage += HelpMessageGroup(_("Chain selection options:"));
+ strUsage += HelpMessageOpt("-testnet", _("Use the test chain"));
+ if (debugHelp) {
+ strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
+ "This is intended for regression testing tools and app development.");
+ }
+}
+
/**
* Main network
*/
@@ -71,31 +86,25 @@ const CBaseChainParams& BaseParams()
return *pCurrentBaseParams;
}
-void SelectBaseParams(CBaseChainParams::Network network)
+void SelectBaseParams(const std::string& chain)
{
- switch (network) {
- case CBaseChainParams::MAIN:
+ if (chain == CBaseChainParams::MAIN)
pCurrentBaseParams = &mainParams;
- break;
- case CBaseChainParams::TESTNET:
+ else if (chain == CBaseChainParams::TESTNET)
pCurrentBaseParams = &testNetParams;
- break;
- case CBaseChainParams::REGTEST:
+ else if (chain == CBaseChainParams::REGTEST)
pCurrentBaseParams = &regTestParams;
- break;
- default:
- assert(false && "Unimplemented network");
- return;
- }
+ else
+ throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
-CBaseChainParams::Network NetworkIdFromCommandLine()
+std::string ChainNameFromCommandLine()
{
bool fRegTest = GetBoolArg("-regtest", false);
bool fTestNet = GetBoolArg("-testnet", false);
if (fTestNet && fRegTest)
- return CBaseChainParams::MAX_NETWORK_TYPES;
+ throw std::runtime_error("Invalid combination of -regtest and -testnet.");
if (fRegTest)
return CBaseChainParams::REGTEST;
if (fTestNet)
@@ -103,16 +112,6 @@ CBaseChainParams::Network NetworkIdFromCommandLine()
return CBaseChainParams::MAIN;
}
-bool SelectBaseParamsFromCommandLine()
-{
- CBaseChainParams::Network network = NetworkIdFromCommandLine();
- if (network == CBaseChainParams::MAX_NETWORK_TYPES)
- return false;
-
- SelectBaseParams(network);
- return true;
-}
-
bool AreBaseParamsConfigured()
{
return pCurrentBaseParams != NULL;
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 4369d0aef7..095c4cbdcb 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -15,13 +15,10 @@
class CBaseChainParams
{
public:
- enum Network {
- MAIN,
- TESTNET,
- REGTEST,
-
- MAX_NETWORK_TYPES
- };
+ /** BIP70 chain name strings (main, test or regtest) */
+ static const std::string MAIN;
+ static const std::string TESTNET;
+ static const std::string REGTEST;
const std::string& DataDir() const { return strDataDir; }
int RPCPort() const { return nRPCPort; }
@@ -34,25 +31,25 @@ protected:
};
/**
+ * Append the help messages for the chainparams options to the
+ * parameter string.
+ */
+void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp=true);
+
+/**
* Return the currently selected parameters. This won't change after app
* startup, except for unit tests.
*/
const CBaseChainParams& BaseParams();
/** Sets the params returned by Params() to those for the given network. */
-void SelectBaseParams(CBaseChainParams::Network network);
-
-/**
- * Looks for -regtest or -testnet and returns the appropriate Network ID.
- * Returns MAX_NETWORK_TYPES if an invalid combination is given.
- */
-CBaseChainParams::Network NetworkIdFromCommandLine();
+void SelectBaseParams(const std::string& chain);
/**
- * Calls NetworkIdFromCommandLine() and then calls SelectParams as appropriate.
- * Returns false if an invalid combination is given.
+ * Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
+ * @return CBaseChainParams::MAX_NETWORK_TYPES if an invalid combination is given. CBaseChainParams::MAIN by default.
*/
-bool SelectBaseParamsFromCommandLine();
+std::string ChainNameFromCommandLine();
/**
* Return true if SelectBaseParamsFromCommandLine() has been called to select
diff --git a/src/compat.h b/src/compat.h
index 5378c2c761..20c2a25143 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <net/if.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <limits.h>
diff --git a/src/consensus/params.h b/src/consensus/params.h
index c480a1cce1..efbbbed352 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -22,6 +22,7 @@ struct Params {
/** Proof of work parameters */
uint256 powLimit;
bool fPowAllowMinDifficultyBlocks;
+ bool fPowNoRetargeting;
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 0a7f903e9f..8698abb900 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -38,6 +38,9 @@
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
+/** Maximum size of http request (request line + headers) */
+static const size_t MAX_HEADERS_SIZE = 8192;
+
/** HTTP request work item */
class HTTPWorkItem : public HTTPClosure
{
@@ -414,6 +417,7 @@ bool InitHTTPServer()
}
evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
+ evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
evhttp_set_max_body_size(http, MAX_SIZE);
evhttp_set_gencb(http, http_request_cb, NULL);
diff --git a/src/init.cpp b/src/init.cpp
index 4460ecb1fa..dd9259d4c9 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -320,6 +320,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
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));
+ strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef WIN32
@@ -439,11 +441,10 @@ std::string HelpMessage(HelpMessageMode mode)
{
strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", 0));
strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", 1));
- strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
- "This is intended for regression testing tools and app development.");
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
- strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
+
+ AppendParamsHelpMessages(strUsage, showDebug);
strUsage += HelpMessageGroup(_("Node relay options:"));
if (showDebug)
@@ -841,6 +842,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = GetBoolArg("-checkpoints", true);
+ // -mempoollimit limits
+ int64_t nMempoolSizeLimit = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t nMempoolDescendantSizeLimit = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
+ if (nMempoolSizeLimit < 0 || nMempoolSizeLimit < nMempoolDescendantSizeLimit * 40)
+ return InitError(strprintf(_("Error: -maxmempool must be at least %d MB"), GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25));
+
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (nScriptCheckThreads <= 0)
diff --git a/src/main.cpp b/src/main.cpp
index 95c71b9cc0..30df2744a3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -75,7 +75,7 @@ uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
-CFeeRate minRelayTxFee = CFeeRate(5000);
+CFeeRate minRelayTxFee = CFeeRate(1000);
CTxMemPool mempool(::minRelayTxFee);
@@ -740,17 +740,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return true;
}
-CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
+CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned int nBytes, bool fAllowFree)
{
- {
- LOCK(mempool.cs);
- uint256 hash = tx.GetHash();
- double dPriorityDelta = 0;
- CAmount nFeeDelta = 0;
- mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- if (dPriorityDelta > 0 || nFeeDelta > 0)
- return 0;
- }
+ uint256 hash = tx.GetHash();
+ double dPriorityDelta = 0;
+ CAmount nFeeDelta = 0;
+ pool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
+ if (dPriorityDelta > 0 || nFeeDelta > 0)
+ return 0;
CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);
@@ -779,7 +776,7 @@ static std::string FormatStateMessage(const CValidationState &state)
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fRejectAbsurdFee)
+ bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
@@ -879,17 +876,20 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
CAmount nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());
- CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx));
+ CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx));
unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
- CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
+ CAmount txMinFee = GetMinRelayFee(tx, pool, nSize, true);
if (fLimitFree && nFees < txMinFee)
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
strprintf("%d < %d", nFees, txMinFee));
- // Require that free transactions have sufficient priority to be mined in the next block.
- if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
+ CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
+ if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
+ } else if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
+ // Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
@@ -954,6 +954,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
+
+ // trim mempool and check if tx was trimmed
+ if (!fOverrideMempoolLimit) {
+ int expired = pool.Expire(GetTime() - GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
+ if (expired != 0)
+ LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);
+
+ pool.TrimToSize(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+ if (!pool.exists(tx.GetHash()))
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full");
+ }
}
SyncWithWallets(tx, NULL);
@@ -1740,11 +1751,18 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
- // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded:
+ // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks,
+ // when 75% of the network has upgraded:
if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
flags |= SCRIPT_VERIFY_DERSIG;
}
+ // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4
+ // blocks, when 75% of the network has upgraded:
+ if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
+ flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
+ }
+
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
@@ -2020,7 +2038,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
}
}
-/** Disconnect chainActive's tip. */
+/** Disconnect chainActive's tip. You want to manually re-limit mempool size after this */
bool static DisconnectTip(CValidationState &state) {
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
@@ -2047,7 +2065,7 @@ bool static DisconnectTip(CValidationState &state) {
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) {
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
mempool.remove(tx, removed, true);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
@@ -2220,9 +2238,11 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
// Disconnect active blocks which are no longer in the best chain.
+ bool fBlocksDisconnected = false;
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
if (!DisconnectTip(state))
return false;
+ fBlocksDisconnected = true;
}
// Build list of new blocks to connect.
@@ -2268,6 +2288,9 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
}
}
+ if (fBlocksDisconnected)
+ mempool.TrimToSize(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
@@ -2354,6 +2377,8 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) {
}
}
+ mempool.TrimToSize(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add it again.
BlockMap::iterator it = mapBlockIndex.begin();
@@ -2684,6 +2709,11 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s : rejected nVersion=2 block", __func__),
REJECT_OBSOLETE, "bad-version");
+ // Reject block.nVersion=3 blocks when 95% (75% on testnet) of the network has upgraded:
+ if (block.nVersion < 4 && IsSuperMajority(4, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
+ return state.Invalid(error("%s : rejected nVersion=3 block", __func__),
+ REJECT_OBSOLETE, "bad-version");
+
return true;
}
@@ -4290,10 +4320,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
- LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u)\n",
+ LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
pfrom->id,
tx.GetHash().ToString(),
- mempool.size());
+ mempool.size(), mempool.DynamicMemoryUsage() / 1000);
// Recursively process any orphan transactions that depended on this one
set<NodeId> setMisbehaving;
@@ -4955,7 +4985,16 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
state.fSyncStarted = true;
nSyncStarted++;
- CBlockIndex *pindexStart = pindexBestHeader->pprev ? pindexBestHeader->pprev : pindexBestHeader;
+ const CBlockIndex *pindexStart = pindexBestHeader;
+ /* If possible, start at the block preceding the currently
+ best known header. This ensures that we always get a
+ non-empty list of headers back as long as the peer
+ is up-to-date. With a non-empty response, we can initialise
+ the peer's known best block. This wouldn't be possible
+ if we requested starting at pindexBestHeader and
+ got back an empty response. */
+ if (pindexStart->pprev)
+ pindexStart = pindexStart->pprev;
LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256());
}
diff --git a/src/main.h b/src/main.h
index a6001eed8f..202d2c772b 100644
--- a/src/main.h
+++ b/src/main.h
@@ -51,6 +51,10 @@ static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 900;
static const unsigned int DEFAULT_DESCENDANT_LIMIT = 1000;
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 2500;
+/** Default for -maxmempool, maximum megabytes of mempool memory usage */
+static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
+/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
+static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
@@ -225,7 +229,7 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fRejectAbsurdFee=false);
+ bool* pfMissingInputs, bool fOverrideMempoolLimit=false, bool fRejectAbsurdFee=false);
struct CNodeStateStats {
diff --git a/src/net.cpp b/src/net.cpp
index 87c4f0af0a..58b946f4a1 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -963,6 +963,15 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
return;
}
+ // According to the internet TCP_NODELAY is not carried into accepted sockets
+ // on all platforms. Set it again here just to be sure.
+ int set = 1;
+#ifdef WIN32
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
+#else
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
+#endif
+
if (CNode::IsBanned(addr) && !whitelisted)
{
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
@@ -1790,8 +1799,11 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
+ // Disable Nagle's algorithm
+ setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int));
#else
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
+ setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int));
#endif
// Set to non-blocking, incoming connections will also inherit this
diff --git a/src/netbase.cpp b/src/netbase.cpp
index c3d56d9184..f5316965ce 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -444,12 +444,19 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (hSocket == INVALID_SOCKET)
return false;
-#ifdef SO_NOSIGPIPE
int set = 1;
+#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
+ //Disable Nagle's algorithm
+#ifdef WIN32
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
+#else
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
+#endif
+
// Set to non-blocking
if (!SetSocketNonBlocking(hSocket, true))
return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
diff --git a/src/pow.cpp b/src/pow.cpp
index bb53ad204b..5ace3fbc9b 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -52,6 +52,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
+ if (params.fPowNoRetargeting)
+ return pindexLast->nBits;
+
// Limit adjustment step
int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan);
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 86106098f5..54731ff557 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -21,7 +21,7 @@ class CBlockHeader
{
public:
// header
- static const int32_t CURRENT_VERSION=3;
+ static const int32_t CURRENT_VERSION=4;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index ea7f86d18e..bda8acff15 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -563,7 +563,7 @@ int main(int argc, char *argv[])
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
- if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
+ if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version"))
{
HelpMessageDialog help(NULL, mapArgs.count("-version"));
help.showOrPrint();
@@ -597,8 +597,10 @@ int main(int argc, char *argv[])
// - Needs to be done before createOptionsModel
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
- if (!SelectParamsFromCommandLine()) {
- QMessageBox::critical(0, QObject::tr("Bitcoin Core"), QObject::tr("Error: Invalid combination of -regtest and -testnet."));
+ try {
+ SelectParams(ChainNameFromCommandLine());
+ } catch(std::exception &e) {
+ QMessageBox::critical(0, QObject::tr("Bitcoin Core"), QObject::tr("Error: %1").arg(e.what()));
return 1;
}
#ifdef ENABLE_WALLET
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 545ac12890..20c0c1fb2f 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -648,6 +648,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
UniValue softforks(UniValue::VARR);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
+ softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
obj.push_back(Pair("softforks", softforks));
if (fPruneMode)
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 4064c2fee3..343b6234d4 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -76,6 +76,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getrawtransaction", 1 },
{ "createrawtransaction", 0 },
{ "createrawtransaction", 1 },
+ { "createrawtransaction", 2 },
{ "signrawtransaction", 1 },
{ "signrawtransaction", 2 },
{ "sendrawtransaction", 1 },
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 4dec53396d..5f3363d097 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -316,9 +316,9 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
UniValue createrawtransaction(const UniValue& params, bool fHelp)
{
- if (fHelp || params.size() != 2)
+ if (fHelp || params.size() < 2 || params.size() > 3)
throw runtime_error(
- "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...}\n"
+ "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
"Returns hex-encoded raw transaction.\n"
@@ -340,6 +340,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
" \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n"
" ...\n"
" }\n"
+ "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
@@ -351,13 +352,22 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
+ if (params[0].isNull() || params[1].isNull())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
UniValue inputs = params[0].get_array();
UniValue sendTo = params[1].get_obj();
CMutableTransaction rawTx;
+ if (params.size() > 2 && !params[2].isNull()) {
+ int64_t nLockTime = params[2].get_int64();
+ if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
+ rawTx.nLockTime = nLockTime;
+ }
+
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
@@ -371,7 +381,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
- CTxIn in(COutPoint(txid, nOutput));
+ uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
+ CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
+
rawTx.vin.push_back(in);
}
@@ -809,7 +821,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) {
+ if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, !fOverrideFees)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 0320577797..a48ff1e18d 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -44,9 +44,10 @@ typedef enum bitcoinconsensus_error_t
/** Script verification flags */
enum
{
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
};
/// Returns 1 if the input nIn of the serialized transaction pointed to by
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index d3aec26020..6a20d497c0 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -273,7 +273,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
// Note how OP_RESERVED does not count towards the opcode limit.
- if (opcode > OP_16 && ++nOpCount > 201)
+ if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
if (opcode == OP_CAT ||
@@ -869,10 +869,10 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
- if (nKeysCount < 0 || nKeysCount > 20)
+ if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG)
return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT);
nOpCount += nKeysCount;
- if (nOpCount > 201)
+ if (nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
int ikey = ++i;
i += nKeysCount;
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 9a0c067a33..263c89defe 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -170,7 +170,7 @@ unsigned int CScript::GetSigOpCount(bool fAccurate) const
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
n += DecodeOP_N(lastOpcode);
else
- n += 20;
+ n += MAX_PUBKEYS_PER_MULTISIG;
}
lastOpcode = opcode;
}
diff --git a/src/script/script.h b/src/script/script.h
index cdc9a71bb2..a38d33a189 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -17,7 +17,14 @@
#include <string>
#include <vector>
-static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
+// Maximum number of bytes pushable to the stack
+static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
+
+// Maximum number of non-push operations per script
+static const int MAX_OPS_PER_SCRIPT = 201;
+
+// Maximum number of public keys per multisig
+static const int MAX_PUBKEYS_PER_MULTISIG = 20;
// Threshold for nLockTime: below this value it is interpreted as block number,
// otherwise as UNIX timestamp.
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index 5cad5af7c3..d3c8594342 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -193,5 +193,9 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+["A transaction with a non-standard DER signature."],
+[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
+"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 9744a3c848..0dfef73ae5 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -229,5 +229,9 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+["A transaction with a non-standard DER signature."],
+[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
+"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 5bf1e98e8f..0cf906a259 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -153,11 +153,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
std::vector<std::string> sortedOrder;
sortedOrder.resize(5);
- sortedOrder[0] = tx2.GetHash().ToString(); // 20000
- sortedOrder[1] = tx4.GetHash().ToString(); // 15000
+ sortedOrder[0] = tx3.GetHash().ToString(); // 0
+ sortedOrder[1] = tx5.GetHash().ToString(); // 10000
sortedOrder[2] = tx1.GetHash().ToString(); // 10000
- sortedOrder[3] = tx5.GetHash().ToString(); // 10000
- sortedOrder[4] = tx3.GetHash().ToString(); // 0
+ sortedOrder[3] = tx4.GetHash().ToString(); // 15000
+ sortedOrder[4] = tx2.GetHash().ToString(); // 20000
CheckSort(pool, sortedOrder);
/* low fee but with high fee child */
@@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
pool.addUnchecked(tx6.GetHash(), CTxMemPoolEntry(tx6, 0LL, 1, 10.0, 1, true));
BOOST_CHECK_EQUAL(pool.size(), 6);
// Check that at this point, tx6 is sorted low
- sortedOrder.push_back(tx6.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
CheckSort(pool, sortedOrder);
CTxMemPool::setEntries setAncestors;
@@ -194,9 +194,9 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_CHECK_EQUAL(pool.size(), 7);
// Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ...
- sortedOrder.erase(sortedOrder.end()-1);
- sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
- sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
+ sortedOrder.erase(sortedOrder.begin());
+ sortedOrder.push_back(tx6.GetHash().ToString());
+ sortedOrder.push_back(tx7.GetHash().ToString());
CheckSort(pool, sortedOrder);
/* low fee child of tx7 */
@@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
pool.addUnchecked(tx8.GetHash(), CTxMemPoolEntry(tx8, 0LL, 2, 10.0, 1, true), setAncestors);
// Now tx8 should be sorted low, but tx6/tx both high
- sortedOrder.push_back(tx8.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
CheckSort(pool, sortedOrder);
/* low fee child of tx7 */
@@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
// tx9 should be sorted low
BOOST_CHECK_EQUAL(pool.size(), 9);
- sortedOrder.push_back(tx9.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());
CheckSort(pool, sortedOrder);
std::vector<std::string> snapshotOrder = sortedOrder;
@@ -255,21 +255,21 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
* tx8 and tx9 should both now be sorted higher
* Final order after tx10 is added:
*
- * tx7 = 2.2M (4 txs)
- * tx6 = 2.2M (5 txs)
- * tx10 = 200k (1 tx)
- * tx8 = 200k (2 txs)
- * tx9 = 200k (2 txs)
- * tx2 = 20000 (1)
- * tx4 = 15000 (1)
- * tx1 = 10000 (1)
- * tx5 = 10000 (1)
* tx3 = 0 (1)
+ * tx5 = 10000 (1)
+ * tx1 = 10000 (1)
+ * tx4 = 15000 (1)
+ * tx2 = 20000 (1)
+ * tx9 = 200k (2 txs)
+ * tx8 = 200k (2 txs)
+ * tx10 = 200k (1 tx)
+ * tx6 = 2.2M (5 txs)
+ * tx7 = 2.2M (4 txs)
*/
- sortedOrder.erase(sortedOrder.end()-2, sortedOrder.end()); // take out tx8, tx9 from the end
- sortedOrder.insert(sortedOrder.begin()+2, tx10.GetHash().ToString()); // tx10 is after tx6
- sortedOrder.insert(sortedOrder.begin()+3, tx9.GetHash().ToString());
- sortedOrder.insert(sortedOrder.begin()+3, tx8.GetHash().ToString());
+ sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin()+2); // take out tx9, tx8 from the beginning
+ sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6
CheckSort(pool, sortedOrder);
// there should be 10 transactions in the mempool
@@ -281,4 +281,157 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
CheckSort(pool, snapshotOrder);
}
+BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
+{
+ CTxMemPool pool(CFeeRate(1000));
+
+ CMutableTransaction tx1 = CMutableTransaction();
+ tx1.vin.resize(1);
+ tx1.vin[0].scriptSig = CScript() << OP_1;
+ tx1.vout.resize(1);
+ tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
+ tx1.vout[0].nValue = 10 * COIN;
+ pool.addUnchecked(tx1.GetHash(), CTxMemPoolEntry(tx1, 10000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx1)));
+
+ CMutableTransaction tx2 = CMutableTransaction();
+ tx2.vin.resize(1);
+ tx2.vin[0].scriptSig = CScript() << OP_2;
+ tx2.vout.resize(1);
+ tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
+ tx2.vout[0].nValue = 10 * COIN;
+ pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 5000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx2)));
+
+ pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
+ BOOST_CHECK(pool.exists(tx1.GetHash()));
+ BOOST_CHECK(pool.exists(tx2.GetHash()));
+
+ pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
+ BOOST_CHECK(pool.exists(tx1.GetHash()));
+ BOOST_CHECK(!pool.exists(tx2.GetHash()));
+
+ pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 5000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx2)));
+ CMutableTransaction tx3 = CMutableTransaction();
+ tx3.vin.resize(1);
+ tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
+ tx3.vin[0].scriptSig = CScript() << OP_2;
+ tx3.vout.resize(1);
+ tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
+ tx3.vout[0].nValue = 10 * COIN;
+ pool.addUnchecked(tx3.GetHash(), CTxMemPoolEntry(tx3, 20000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx3)));
+
+ pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
+ BOOST_CHECK(!pool.exists(tx1.GetHash()));
+ BOOST_CHECK(pool.exists(tx2.GetHash()));
+ BOOST_CHECK(pool.exists(tx3.GetHash()));
+
+ pool.TrimToSize(::GetSerializeSize(CTransaction(tx1), SER_NETWORK, PROTOCOL_VERSION)); // mempool is limited to tx1's size in memory usage, so nothing fits
+ BOOST_CHECK(!pool.exists(tx1.GetHash()));
+ BOOST_CHECK(!pool.exists(tx2.GetHash()));
+ BOOST_CHECK(!pool.exists(tx3.GetHash()));
+
+ CFeeRate maxFeeRateRemoved(25000, ::GetSerializeSize(CTransaction(tx3), SER_NETWORK, PROTOCOL_VERSION) + ::GetSerializeSize(CTransaction(tx2), SER_NETWORK, PROTOCOL_VERSION));
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
+
+ CMutableTransaction tx4 = CMutableTransaction();
+ tx4.vin.resize(2);
+ tx4.vin[0].prevout.SetNull();
+ tx4.vin[0].scriptSig = CScript() << OP_4;
+ tx4.vin[1].prevout.SetNull();
+ tx4.vin[1].scriptSig = CScript() << OP_4;
+ tx4.vout.resize(2);
+ tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
+ tx4.vout[0].nValue = 10 * COIN;
+ tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
+ tx4.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx5 = CMutableTransaction();
+ tx5.vin.resize(2);
+ tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
+ tx5.vin[0].scriptSig = CScript() << OP_4;
+ tx5.vin[1].prevout.SetNull();
+ tx5.vin[1].scriptSig = CScript() << OP_5;
+ tx5.vout.resize(2);
+ tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
+ tx5.vout[0].nValue = 10 * COIN;
+ tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
+ tx5.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx6 = CMutableTransaction();
+ tx6.vin.resize(2);
+ tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
+ tx6.vin[0].scriptSig = CScript() << OP_4;
+ tx6.vin[1].prevout.SetNull();
+ tx6.vin[1].scriptSig = CScript() << OP_6;
+ tx6.vout.resize(2);
+ tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
+ tx6.vout[0].nValue = 10 * COIN;
+ tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
+ tx6.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx7 = CMutableTransaction();
+ tx7.vin.resize(2);
+ tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
+ tx7.vin[0].scriptSig = CScript() << OP_5;
+ tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
+ tx7.vin[1].scriptSig = CScript() << OP_6;
+ tx7.vout.resize(2);
+ tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[0].nValue = 10 * COIN;
+ tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[0].nValue = 10 * COIN;
+
+ pool.addUnchecked(tx4.GetHash(), CTxMemPoolEntry(tx4, 7000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx4)));
+ pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5)));
+ pool.addUnchecked(tx6.GetHash(), CTxMemPoolEntry(tx6, 1100LL, 0, 10.0, 1, pool.HasNoInputsOf(tx6)));
+ pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 9000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx7)));
+
+ // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that
+ pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
+ BOOST_CHECK(pool.exists(tx4.GetHash()));
+ BOOST_CHECK(pool.exists(tx6.GetHash()));
+ BOOST_CHECK(!pool.exists(tx7.GetHash()));
+
+ if (!pool.exists(tx5.GetHash()))
+ pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5)));
+ pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 9000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx7)));
+
+ pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
+ BOOST_CHECK(pool.exists(tx4.GetHash()));
+ BOOST_CHECK(!pool.exists(tx5.GetHash()));
+ BOOST_CHECK(pool.exists(tx6.GetHash()));
+ BOOST_CHECK(!pool.exists(tx7.GetHash()));
+
+ pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 1000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx5)));
+ pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 9000LL, 0, 10.0, 1, pool.HasNoInputsOf(tx7)));
+
+ std::vector<CTransaction> vtx;
+ std::list<CTransaction> conflicts;
+ SetMockTime(42);
+ SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
+ // ... we should keep the same min fee until we get a block
+ pool.removeForBlock(vtx, 1, conflicts);
+ SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
+ // ... then feerate should drop 1/2 each halflife
+
+ SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4);
+ // ... with a 1/2 halflife when mempool is < 1/2 its target size
+
+ SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8);
+ // ... with a 1/4 halflife when mempool is < 1/4 its target size
+
+ SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000);
+ // ... but feerate should never drop below 1000
+
+ SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
+ // ... unless it has gone all the way to 0 (after getting past 1000/2)
+
+ SetMockTime(0);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 8d81275a6f..a74fbfc0d7 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -32,13 +32,13 @@ CWallet* pwalletMain;
extern bool fPrintToConsole;
extern void noui_connect();
-BasicTestingSetup::BasicTestingSetup(CBaseChainParams::Network network)
+BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
{
ECC_Start();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
- SelectParams(network);
+ SelectParams(chainName);
noui_connect();
}
@@ -47,7 +47,7 @@ BasicTestingSetup::~BasicTestingSetup()
ECC_Stop();
}
-TestingSetup::TestingSetup(CBaseChainParams::Network network) : BasicTestingSetup(network)
+TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
{
#ifdef ENABLE_WALLET
bitdb.MakeMock();
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index b9314d0611..0bab4b6831 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -12,7 +12,7 @@
* This just configures logging and chain parameters.
*/
struct BasicTestingSetup {
- BasicTestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN);
+ BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
@@ -25,7 +25,7 @@ struct TestingSetup: public BasicTestingSetup {
boost::filesystem::path pathTemp;
boost::thread_group threadGroup;
- TestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN);
+ TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
};
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index edad18644e..9b8e1c088b 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, false);
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, false);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 1370cab0c0..bb148005cd 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -13,6 +13,7 @@
#include "streams.h"
#include "util.h"
#include "utilmoneystr.h"
+#include "utiltime.h"
#include "version.h"
using namespace std;
@@ -305,15 +306,18 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
}
}
-CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) :
+CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
nTransactionsUpdated(0)
{
+ clear();
+
// Sanity checks off by default for performance, because otherwise
// accepting transactions becomes O(N^2) where N is the number
// of transactions in the pool
fSanityCheck = false;
- minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee);
+ minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee);
+ minReasonableRelayFee = _minReasonableRelayFee;
}
CTxMemPool::~CTxMemPool()
@@ -538,6 +542,8 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i
}
// After the txs in the new block have been removed from the mempool, update policy estimates
minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate);
+ lastRollingFeeUpdate = GetTime();
+ blockSinceLastRollingFeeBump = true;
}
void CTxMemPool::clear()
@@ -548,6 +554,9 @@ void CTxMemPool::clear()
mapNextTx.clear();
totalTxSize = 0;
cachedInnerUsage = 0;
+ lastRollingFeeUpdate = GetTime();
+ blockSinceLastRollingFeeBump = false;
+ rollingMinimumFeeRate = 0;
++nTransactionsUpdated;
}
@@ -735,10 +744,10 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash,
LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
}
-void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta)
+void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const
{
LOCK(cs);
- std::map<uint256, std::pair<double, CAmount> >::iterator pos = mapDeltas.find(hash);
+ std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
if (pos == mapDeltas.end())
return;
const std::pair<double, CAmount> &deltas = pos->second;
@@ -792,6 +801,22 @@ void CTxMemPool::RemoveStaged(setEntries &stage) {
}
}
+int CTxMemPool::Expire(int64_t time) {
+ LOCK(cs);
+ indexed_transaction_set::nth_index<2>::type::iterator it = mapTx.get<2>().begin();
+ setEntries toremove;
+ while (it != mapTx.get<2>().end() && it->GetTime() < time) {
+ toremove.insert(mapTx.project<0>(it));
+ it++;
+ }
+ setEntries stage;
+ BOOST_FOREACH(txiter removeit, toremove) {
+ CalculateDescendants(removeit, stage);
+ }
+ RemoveStaged(stage);
+ return stage.size();
+}
+
bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate)
{
LOCK(cs);
@@ -837,3 +862,62 @@ const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) cons
assert(it != mapLinks.end());
return it->second.children;
}
+
+CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
+ LOCK(cs);
+ if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
+ return CFeeRate(rollingMinimumFeeRate);
+
+ int64_t time = GetTime();
+ if (time > lastRollingFeeUpdate + 10) {
+ double halflife = ROLLING_FEE_HALFLIFE;
+ if (DynamicMemoryUsage() < sizelimit / 4)
+ halflife /= 4;
+ else if (DynamicMemoryUsage() < sizelimit / 2)
+ halflife /= 2;
+
+ rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
+ lastRollingFeeUpdate = time;
+
+ if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) {
+ rollingMinimumFeeRate = 0;
+ return CFeeRate(0);
+ }
+ }
+ return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee);
+}
+
+void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
+ AssertLockHeld(cs);
+ if (rate.GetFeePerK() > rollingMinimumFeeRate) {
+ rollingMinimumFeeRate = rate.GetFeePerK();
+ blockSinceLastRollingFeeBump = false;
+ }
+}
+
+void CTxMemPool::TrimToSize(size_t sizelimit) {
+ LOCK(cs);
+
+ unsigned nTxnRemoved = 0;
+ CFeeRate maxFeeRateRemoved(0);
+ while (DynamicMemoryUsage() > sizelimit) {
+ indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin();
+
+ // We set the new mempool min fee to the feerate of the removed set, plus the
+ // "minimum reasonable fee rate" (ie some value under which we consider txn
+ // to have 0 fee). This way, we don't allow txn to enter mempool with feerate
+ // equal to txn which were removed with no block in between.
+ CFeeRate removed(it->GetFeesWithDescendants(), it->GetSizeWithDescendants());
+ removed += minReasonableRelayFee;
+ trackPackageRemoved(removed);
+ maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
+
+ setEntries stage;
+ CalculateDescendants(mapTx.project<0>(it), stage);
+ RemoveStaged(stage);
+ nTxnRemoved += stage.size();
+ }
+
+ if (maxFeeRateRemoved > CFeeRate(0))
+ LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString());
+}
diff --git a/src/txmempool.h b/src/txmempool.h
index c0eef0dd22..d44995eefe 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -83,7 +83,7 @@ public:
const CTransaction& GetTx() const { return this->tx; }
double GetPriority(unsigned int currentHeight) const;
- CAmount GetFee() const { return nFee; }
+ const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const { return nTxSize; }
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return nHeight; }
@@ -160,9 +160,9 @@ public:
double f2 = aSize * bFees;
if (f1 == f2) {
- return a.GetTime() < b.GetTime();
+ return a.GetTime() >= b.GetTime();
}
- return f1 > f2;
+ return f1 < f2;
}
// Calculate which feerate to use for an entry (avoiding division).
@@ -211,9 +211,10 @@ public:
*
* CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
*
- * mapTx is a boost::multi_index that sorts the mempool on 2 criteria:
+ * mapTx is a boost::multi_index that sorts the mempool on 3 criteria:
* - transaction hash
* - feerate [we use max(feerate of tx, feerate of tx with all descendants)]
+ * - time in mempool
*
* Note: the term "descendant" refers to in-mempool transactions that depend on
* this one, while "ancestor" refers to in-mempool transactions that a given
@@ -284,7 +285,18 @@ private:
uint64_t totalTxSize; //! sum of all mempool tx' byte sizes
uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves)
+ CFeeRate minReasonableRelayFee;
+
+ mutable int64_t lastRollingFeeUpdate;
+ mutable bool blockSinceLastRollingFeeBump;
+ mutable double rollingMinimumFeeRate; //! minimum fee to get into the pool, decreases exponentially
+
+ void trackPackageRemoved(const CFeeRate& rate);
+
public:
+
+ static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing
+
typedef boost::multi_index_container<
CTxMemPoolEntry,
boost::multi_index::indexed_by<
@@ -294,6 +306,11 @@ public:
boost::multi_index::ordered_non_unique<
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByFee
+ >,
+ // sorted by entry time
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::identity<CTxMemPoolEntry>,
+ CompareTxMemPoolEntryByEntryTime
>
>
> indexed_transaction_set;
@@ -328,7 +345,12 @@ public:
std::map<COutPoint, CInPoint> mapNextTx;
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
- CTxMemPool(const CFeeRate& _minRelayFee);
+ /** Create a new CTxMemPool.
+ * minReasonableRelayFee should be a feerate which is, roughly, somewhere
+ * around what it "costs" to relay a transaction around the network and
+ * below which we would reasonably say a transaction has 0-effective-fee.
+ */
+ CTxMemPool(const CFeeRate& _minReasonableRelayFee);
~CTxMemPool();
/**
@@ -365,7 +387,7 @@ public:
/** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta);
- void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta);
+ void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const;
void ClearPrioritisation(const uint256 hash);
public:
@@ -397,6 +419,20 @@ public:
*/
bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true);
+ /** The minimum fee to get into the mempool, which may itself not be enough
+ * for larger-sized transactions.
+ * The minReasonableRelayFee constructor arg is used to bound the time it
+ * takes the fee rate to go back down all the way to 0. When the feerate
+ * would otherwise be half of this, it is set to 0 instead.
+ */
+ CFeeRate GetMinFee(size_t sizelimit) const;
+
+ /** Remove transactions from the mempool until its dynamic size is <= sizelimit. */
+ void TrimToSize(size_t sizelimit);
+
+ /** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */
+ int Expire(int64_t time);
+
unsigned long size()
{
LOCK(cs);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index bd3004061b..3f2d5a05f6 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2863,6 +2863,6 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, fRejectAbsurdFee);
}