aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac22
-rwxr-xr-xqa/pull-tester/build-tests.sh.in4
-rwxr-xr-xqa/pull-tester/pull-tester.py4
-rwxr-xr-xqa/pull-tester/pull-tester.sh4
-rwxr-xr-xqa/pull-tester/run-bitcoind-for-test.sh.in4
-rwxr-xr-xqa/rpc-tests/conflictedbalance.sh2
-rwxr-xr-xqa/rpc-tests/forknotify.py2
-rwxr-xr-xqa/rpc-tests/getblocktemplate.py2
-rwxr-xr-xqa/rpc-tests/getchaintips.py2
-rwxr-xr-xqa/rpc-tests/keypool.py2
-rwxr-xr-xqa/rpc-tests/listtransactions.py2
-rw-r--r--qa/rpc-tests/netutil.py5
-rwxr-xr-xqa/rpc-tests/receivedby.py2
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py2
-rwxr-xr-xqa/rpc-tests/send.sh2
-rwxr-xr-xqa/rpc-tests/smartfees.py3
-rwxr-xr-xqa/rpc-tests/test_framework.py2
-rwxr-xr-xqa/rpc-tests/txnmall.sh2
-rw-r--r--qa/rpc-tests/util.py13
-rw-r--r--qa/rpc-tests/util.sh2
-rwxr-xr-xqa/rpc-tests/wallet.sh2
-rwxr-xr-xqa/rpc-tests/walletbackup.sh2
-rwxr-xr-xqa/rpc-tests/zapwallettxes.sh3
-rw-r--r--src/Makefile.am34
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/addrman.cpp1
-rw-r--r--src/allocators.h4
-rw-r--r--src/amount.cpp31
-rw-r--r--src/amount.h43
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bloom.cpp3
-rw-r--r--src/chain.h2
-rw-r--r--src/chainparams.h2
-rw-r--r--src/coincontrol.h2
-rw-r--r--src/coins.h3
-rw-r--r--src/compressor.cpp (renamed from src/script/compressor.cpp)55
-rw-r--r--src/compressor.h (renamed from src/script/compressor.h)36
-rw-r--r--src/core.cpp339
-rw-r--r--src/core.h566
-rw-r--r--src/core/block.cpp130
-rw-r--r--src/core/block.h168
-rw-r--r--src/core/transaction.cpp142
-rw-r--r--src/core/transaction.h276
-rw-r--r--src/core_read.cpp3
-rw-r--r--src/core_write.cpp3
-rw-r--r--src/db.h1
-rw-r--r--src/ecwrapper.cpp333
-rw-r--r--src/ecwrapper.h46
-rw-r--r--src/init.cpp1
-rw-r--r--src/key.cpp372
-rw-r--r--src/key.h139
-rw-r--r--src/keystore.cpp4
-rw-r--r--src/keystore.h12
-rw-r--r--src/leveldb/CONTRIBUTING.md36
-rw-r--r--src/leveldb/Makefile28
-rw-r--r--src/leveldb/README.md138
-rwxr-xr-xsrc/leveldb/build_detect_platform15
-rw-r--r--src/leveldb/db/db_bench.cc3
-rw-r--r--src/leveldb/db/db_impl.cc4
-rw-r--r--src/leveldb/db/db_test.cc2
-rw-r--r--src/leveldb/db/dbformat.h6
-rw-r--r--src/leveldb/db/dumpfile.cc225
-rw-r--r--src/leveldb/db/leveldb_main.cc204
-rw-r--r--src/leveldb/db/log_format.h4
-rw-r--r--src/leveldb/db/log_reader.cc6
-rw-r--r--src/leveldb/db/log_reader.h4
-rw-r--r--src/leveldb/db/log_test.cc2
-rw-r--r--src/leveldb/db/repair.cc2
-rw-r--r--src/leveldb/db/skiplist.h5
-rw-r--r--src/leveldb/db/write_batch_internal.h4
-rw-r--r--src/leveldb/doc/bench/db_bench_tree_db.cc2
-rw-r--r--src/leveldb/doc/impl.html4
-rw-r--r--src/leveldb/doc/log_format.txt6
-rw-r--r--src/leveldb/helpers/memenv/memenv.cc9
-rw-r--r--src/leveldb/include/leveldb/cache.h2
-rw-r--r--src/leveldb/include/leveldb/db.h2
-rw-r--r--src/leveldb/include/leveldb/dumpfile.h25
-rw-r--r--src/leveldb/include/leveldb/env.h2
-rw-r--r--src/leveldb/include/leveldb/iterator.h2
-rw-r--r--src/leveldb/include/leveldb/options.h2
-rw-r--r--src/leveldb/port/atomic_pointer.h21
-rw-r--r--src/leveldb/port/port_posix.h9
-rw-r--r--src/leveldb/port/thread_annotations.h5
-rw-r--r--src/leveldb/table/block.cc2
-rw-r--r--src/leveldb/table/block_builder.h2
-rw-r--r--src/leveldb/table/format.cc2
-rw-r--r--src/leveldb/table/table.cc14
-rw-r--r--src/leveldb/util/bloom.cc2
-rw-r--r--src/leveldb/util/env_posix.cc10
-rw-r--r--src/leveldb/util/hash.cc6
-rw-r--r--src/leveldb/util/hash_test.cc54
-rw-r--r--src/leveldb/util/logging.cc9
-rw-r--r--src/leveldb/util/logging.h4
-rw-r--r--src/leveldbwrapper.h1
-rw-r--r--src/main.cpp4
-rw-r--r--src/main.h6
-rw-r--r--src/miner.cpp4
-rw-r--r--src/net.cpp2
-rw-r--r--src/net.h1
-rw-r--r--src/pow.cpp2
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/optionsmodel.cpp1
-rw-r--r--src/qt/recentrequeststablemodel.cpp1
-rw-r--r--src/rpcblockchain.cpp3
-rw-r--r--src/rpcmining.cpp1
-rw-r--r--src/rpcrawtransaction.cpp2
-rw-r--r--src/rpcwallet.cpp1
-rw-r--r--src/script/interpreter.cpp57
-rw-r--r--src/script/interpreter.h10
-rw-r--r--src/script/script.cpp31
-rw-r--r--src/script/script.h35
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/standard.h1
-rw-r--r--src/serialize.h553
-rw-r--r--src/streams.h571
-rw-r--r--src/test/alert_tests.cpp1
-rw-r--r--src/test/compress_tests.cpp2
-rw-r--r--src/test/data/script_invalid.json113
-rw-r--r--src/test/data/script_valid.json147
-rw-r--r--src/test/main_tests.cpp2
-rw-r--r--src/test/script_tests.cpp33
-rw-r--r--src/test/scriptnum_tests.cpp4
-rw-r--r--src/test/serialize_tests.cpp1
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/test/util_tests.cpp2
-rw-r--r--src/txdb.cpp3
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/txmempool.h5
-rw-r--r--src/undo.h71
-rw-r--r--src/utilmoneystr.cpp2
-rw-r--r--src/wallet.cpp4
-rw-r--r--src/wallet.h12
135 files changed, 3131 insertions, 2301 deletions
diff --git a/configure.ac b/configure.ac
index 90aa112421..b603d1766d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,8 +11,21 @@ AC_CONFIG_SRCDIR([src/main.cpp])
AC_CONFIG_HEADERS([src/config/bitcoin-config.h])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
-LT_INIT([disable-shared])
+
AC_CANONICAL_HOST
+
+dnl By default, libtool for mingw refuses to link static libs into a dll for
+dnl fear of mixing pic/non-pic objects, and import/export complications. Since
+dnl we have those under control, re-enable that functionality.
+
+case $host in
+ *mingw*)
+ lt_cv_deplibs_check_method="pass_all"
+ ;;
+esac
+
+LT_INIT([disable-shared])
+
AH_TOP([#ifndef BITCOIN_CONFIG_H])
AH_TOP([#define BITCOIN_CONFIG_H])
AH_BOTTOM([#endif //BITCOIN_CONFIG_H])
@@ -462,7 +475,7 @@ dnl Check for libminiupnpc (optional)
if test x$use_upnp != xno; then
AC_CHECK_HEADERS(
[miniupnpc/miniwget.h miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h],
- [AC_CHECK_LIB([miniupnpc], [main],, [have_miniupnpc=no])],
+ [AC_CHECK_LIB([miniupnpc], [main],[MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])],
[have_miniupnpc=no]
)
fi
@@ -632,9 +645,9 @@ else
AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),)
AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing))
- BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],,BITCOIN_QT_FAIL(libprotobuf not found)))
+ BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], BITCOIN_QT_FAIL(libprotobuf not found)))
if test x$use_qr != xno; then
- BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],, [have_qrencode=no])])
+ BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])])
BITCOIN_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)])
fi
fi
@@ -808,6 +821,7 @@ AC_SUBST(BUILD_TEST)
AC_SUBST(BUILD_QT)
AC_SUBST(BUILD_TEST_QT)
AC_SUBST(MINIUPNPC_CPPFLAGS)
+AC_SUBST(MINIUPNPC_LIBS)
AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh])
AC_CONFIG_FILES([qa/pull-tester/build-tests.sh],[chmod +x qa/pull-tester/build-tests.sh])
diff --git a/qa/pull-tester/build-tests.sh.in b/qa/pull-tester/build-tests.sh.in
index 1ef47d77f4..f5c5f0bf70 100755
--- a/qa/pull-tester/build-tests.sh.in
+++ b/qa/pull-tester/build-tests.sh.in
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2013 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Copyright (c) 2013-2014 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Param1: The prefix to mingw staging
diff --git a/qa/pull-tester/pull-tester.py b/qa/pull-tester/pull-tester.py
index 61ce813d80..66688dd4b5 100755
--- a/qa/pull-tester/pull-tester.py
+++ b/qa/pull-tester/pull-tester.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
-# Copyright (c) 2013 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Copyright (c) 2013-2014 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 json
diff --git a/qa/pull-tester/pull-tester.sh b/qa/pull-tester/pull-tester.sh
index d3356f736a..3fe4a05c76 100755
--- a/qa/pull-tester/pull-tester.sh
+++ b/qa/pull-tester/pull-tester.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-# Copyright (c) 2013 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Copyright (c) 2013-2014 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Helper script for pull-tester.
diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in
index 15363d09a6..42d8ad52e8 100755
--- a/qa/pull-tester/run-bitcoind-for-test.sh.in
+++ b/qa/pull-tester/run-bitcoind-for-test.sh.in
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2013 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Copyright (c) 2013-2014 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
DATADIR="@abs_top_builddir@/.bitcoin"
diff --git a/qa/rpc-tests/conflictedbalance.sh b/qa/rpc-tests/conflictedbalance.sh
index 849ad31fb8..71761321ed 100755
--- a/qa/rpc-tests/conflictedbalance.sh
+++ b/qa/rpc-tests/conflictedbalance.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test marking of spent outputs
diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py
index 23bfb74175..a4c2dc944e 100755
--- a/qa/rpc-tests/forknotify.py
+++ b/qa/rpc-tests/forknotify.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/qa/rpc-tests/getblocktemplate.py b/qa/rpc-tests/getblocktemplate.py
index 5ae5d09601..500662bf87 100755
--- a/qa/rpc-tests/getblocktemplate.py
+++ b/qa/rpc-tests/getblocktemplate.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Exercise the listtransactions API
diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py
index 842fcad2b2..dda3450eb6 100755
--- a/qa/rpc-tests/getchaintips.py
+++ b/qa/rpc-tests/getchaintips.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Exercise the getchaintips API. We introduce a network split, work
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index 86ad20de52..354ee0822c 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Exercise the wallet keypool, and interaction with wallet encryption/locking
diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py
index 6102052a6f..530b00db8f 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/qa/rpc-tests/listtransactions.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Exercise the listtransactions API
diff --git a/qa/rpc-tests/netutil.py b/qa/rpc-tests/netutil.py
index 9bea2e355e..b740ee0f98 100644
--- a/qa/rpc-tests/netutil.py
+++ b/qa/rpc-tests/netutil.py
@@ -1,3 +1,8 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
# Linux network utilities
import sys
import socket
diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py
index 7170255242..9fc661fe80 100755
--- a/qa/rpc-tests/receivedby.py
+++ b/qa/rpc-tests/receivedby.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Exercise the listreceivedbyaddress API
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index a823404e00..5e476e2505 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test for -rpcbind, as well as -rpcallowip and -rpcconnect
diff --git a/qa/rpc-tests/send.sh b/qa/rpc-tests/send.sh
index 37367865c1..2d54cc6ded 100755
--- a/qa/rpc-tests/send.sh
+++ b/qa/rpc-tests/send.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
TIMEOUT=10
SIGNAL=HUP
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index 065bdb01c3..57a72dd96b 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/qa/rpc-tests/smartfees.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2014 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 fee estimation code
diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py
index 8c8453054d..c3396a5a83 100755
--- a/qa/rpc-tests/test_framework.py
+++ b/qa/rpc-tests/test_framework.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Base class for RPC testing
diff --git a/qa/rpc-tests/txnmall.sh b/qa/rpc-tests/txnmall.sh
index bd36967a63..035e7ee15f 100755
--- a/qa/rpc-tests/txnmall.sh
+++ b/qa/rpc-tests/txnmall.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test proper accounting with malleable transactions
diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py
index 036ac577e6..6d0b21c927 100644
--- a/qa/rpc-tests/util.py
+++ b/qa/rpc-tests/util.py
@@ -1,5 +1,5 @@
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Helpful routines for regression testing
@@ -110,11 +110,14 @@ def initialize_chain(test_dir):
rpcs[i].setgenerate(True, 25)
sync_blocks(rpcs)
- # Shut them down, and remove debug.logs:
+ # Shut them down, and clean up cache directories:
stop_nodes(rpcs)
wait_bitcoinds()
for i in range(4):
- os.remove(debug_log("cache", i))
+ os.remove(log_filename("cache", i, "debug.log"))
+ os.remove(log_filename("cache", i, "db.log"))
+ os.remove(log_filename("cache", i, "peers.dat"))
+ os.remove(log_filename("cache", i, "fee_estimates.dat"))
for i in range(4):
from_dir = os.path.join("cache", "node"+str(i))
@@ -167,8 +170,8 @@ def start_nodes(num_nodes, dir, extra_args=None, rpchost=None):
if extra_args is None: extra_args = [ None for i in range(num_nodes) ]
return [ start_node(i, dir, extra_args[i], rpchost) for i in range(num_nodes) ]
-def debug_log(dir, n_node):
- return os.path.join(dir, "node"+str(n_node), "regtest", "debug.log")
+def log_filename(dir, n_node, logname):
+ return os.path.join(dir, "node"+str(n_node), "regtest", logname)
def stop_node(node, i):
node.stop()
diff --git a/qa/rpc-tests/util.sh b/qa/rpc-tests/util.sh
index b726ef627f..c2b7004308 100644
--- a/qa/rpc-tests/util.sh
+++ b/qa/rpc-tests/util.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Functions used by more than one test
diff --git a/qa/rpc-tests/wallet.sh b/qa/rpc-tests/wallet.sh
index 98532fa858..bb5f34f590 100755
--- a/qa/rpc-tests/wallet.sh
+++ b/qa/rpc-tests/wallet.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (c) 2013-2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test block generation and basic wallet sending
diff --git a/qa/rpc-tests/walletbackup.sh b/qa/rpc-tests/walletbackup.sh
index b88d5920f7..ee11418bef 100755
--- a/qa/rpc-tests/walletbackup.sh
+++ b/qa/rpc-tests/walletbackup.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (c) 2014 The Bitcoin Core developers
-# Distributed under the MIT/X11 software license, see the accompanying
+# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test wallet backup / dump / restore functionality
diff --git a/qa/rpc-tests/zapwallettxes.sh b/qa/rpc-tests/zapwallettxes.sh
index bc52a7dacd..e6d490cccc 100755
--- a/qa/rpc-tests/zapwallettxes.sh
+++ b/qa/rpc-tests/zapwallettxes.sh
@@ -1,4 +1,7 @@
#!/usr/bin/env bash
+# Copyright (c) 2014 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 -zapwallettxes=<mode>
diff --git a/src/Makefile.am b/src/Makefile.am
index 155adfef7d..91cc1b96e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,13 +36,15 @@ LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
LIBBITCOIN_UNIVALUE=univalue/libbitcoin_univalue.a
LIBBITCOINQT=qt/libbitcoinqt.a
+# Make is not made aware of per-object dependencies to avoid limiting building parallelization
+# But to build the less dependent modules first, we manually select their order here:
noinst_LIBRARIES = \
- libbitcoin_server.a \
- libbitcoin_common.a \
- libbitcoin_cli.a \
+ crypto/libbitcoin_crypto.a \
libbitcoin_util.a \
+ libbitcoin_common.a \
univalue/libbitcoin_univalue.a \
- crypto/libbitcoin_crypto.a
+ libbitcoin_server.a \
+ libbitcoin_cli.a
if ENABLE_WALLET
BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
noinst_LIBRARIES += libbitcoin_wallet.a
@@ -78,10 +80,13 @@ BITCOIN_CORE_H = \
coincontrol.h \
coins.h \
compat.h \
- core.h \
+ compressor.h \
+ core/block.h \
+ core/transaction.h \
core_io.h \
crypter.h \
db.h \
+ ecwrapper.h \
hash.h \
init.h \
key.h \
@@ -100,13 +105,13 @@ BITCOIN_CORE_H = \
rpcclient.h \
rpcprotocol.h \
rpcserver.h \
- script/compressor.h \
script/interpreter.h \
script/script.h \
script/sigcache.h \
script/sign.h \
script/standard.h \
serialize.h \
+ streams.h \
sync.h \
threadsafety.h \
timedata.h \
@@ -115,6 +120,7 @@ BITCOIN_CORE_H = \
txmempool.h \
ui_interface.h \
uint256.h \
+ undo.h \
util.h \
utilstrencodings.h \
utilmoneystr.h \
@@ -205,18 +211,21 @@ univalue_libbitcoin_univalue_a_SOURCES = \
libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_common_a_SOURCES = \
allocators.cpp \
+ amount.cpp \
base58.cpp \
chainparams.cpp \
coins.cpp \
- core.cpp \
+ compressor.cpp \
+ core/block.cpp \
+ core/transaction.cpp \
core_read.cpp \
core_write.cpp \
+ ecwrapper.cpp \
hash.cpp \
key.cpp \
keystore.cpp \
netbase.cpp \
protocol.cpp \
- script/compressor.cpp \
script/interpreter.cpp \
script/script.cpp \
script/sigcache.cpp \
@@ -281,7 +290,7 @@ if TARGET_WINDOWS
bitcoind_SOURCES += bitcoind-res.rc
endif
-bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
+bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES)
bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS)
@@ -293,7 +302,8 @@ bitcoin_cli_LDADD = \
$(LIBBITCOIN_CRYPTO) \
$(BOOST_LIBS) \
$(SSL_LIBS) \
- $(CRYPTO_LIBS)
+ $(CRYPTO_LIBS) \
+ $(MINIUPNPC_LIBS)
bitcoin_cli_SOURCES = \
bitcoin-cli.cpp
@@ -317,7 +327,9 @@ endif
bitcoin_tx_LDADD += $(BOOST_LIBS) \
$(SSL_LIBS) \
- $(CRYPTO_LIBS)
+ $(CRYPTO_LIBS) \
+ $(MINIUPNPC_LIBS)
+
bitcoin_tx_SOURCES = bitcoin-tx.cpp
bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
#
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 8fb4af81ac..ac6d60df03 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -360,7 +360,7 @@ if ENABLE_WALLET
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
if USE_LIBSECP256K1
qt_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
endif
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 23375bef82..064b531b93 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -32,7 +32,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
+ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
if USE_LIBSECP256K1
qt_test_test_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
endif
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index b20e226c3d..340eb9f1a7 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -89,7 +89,7 @@ if USE_LIBSECP256K1
test_test_bitcoin_LDADD += secp256k1/libsecp256k1.la
endif
-test_test_bitcoin_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
+test_test_bitcoin_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS)
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 7ff21b00ec..1982db52ae 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -6,6 +6,7 @@
#include "hash.h"
#include "serialize.h"
+#include "streams.h"
using namespace std;
diff --git a/src/allocators.h b/src/allocators.h
index 6b69e7ae69..78a3b76d0c 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -9,6 +9,7 @@
#include <map>
#include <string>
#include <string.h>
+#include <vector>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
@@ -261,4 +262,7 @@ struct zero_after_free_allocator : public std::allocator<T> {
// This is exactly like std::string, but with a custom allocator.
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
+// Byte-vector that clears its contents before deletion.
+typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
+
#endif // BITCOIN_ALLOCATORS_H
diff --git a/src/amount.cpp b/src/amount.cpp
new file mode 100644
index 0000000000..e6f5b7d440
--- /dev/null
+++ b/src/amount.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "amount.h"
+
+#include "tinyformat.h"
+
+CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
+{
+ if (nSize > 0)
+ nSatoshisPerK = nFeePaid*1000/nSize;
+ else
+ nSatoshisPerK = 0;
+}
+
+CAmount CFeeRate::GetFee(size_t nSize) const
+{
+ CAmount nFee = nSatoshisPerK*nSize / 1000;
+
+ if (nFee == 0 && nSatoshisPerK > 0)
+ nFee = nSatoshisPerK;
+
+ return nFee;
+}
+
+std::string CFeeRate::ToString() const
+{
+ return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN);
+}
diff --git a/src/amount.h b/src/amount.h
index 831fa1f6ca..c0d37954cb 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -6,8 +6,49 @@
#ifndef BITCOIN_AMOUNT_H
#define BITCOIN_AMOUNT_H
-#include <stdint.h>
+#include "serialize.h"
+
+#include <stdlib.h>
+#include <string>
typedef int64_t CAmount;
+static const CAmount COIN = 100000000;
+static const CAmount CENT = 1000000;
+
+/** No amount larger than this (in satoshi) is valid */
+static const CAmount MAX_MONEY = 21000000 * COIN;
+inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
+
+/** Type-safe wrapper class to for fee rates
+ * (how much to pay based on transaction size)
+ */
+class CFeeRate
+{
+private:
+ CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
+public:
+ CFeeRate() : nSatoshisPerK(0) { }
+ explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
+ CFeeRate(const CAmount& nFeePaid, size_t nSize);
+ CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
+
+ CAmount GetFee(size_t size) const; // unit returned is satoshis
+ CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes
+
+ 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; }
+ 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; }
+ std::string ToString() const;
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(nSatoshisPerK);
+ }
+};
+
#endif // BITCOIN_AMOUNT_H
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index da37e60c7f..6f3409edf3 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
-#include "core.h"
+#include "core/transaction.h"
#include "core_io.h"
#include "keystore.h"
#include "main.h" // for MAX_BLOCK_SIZE
diff --git a/src/bloom.cpp b/src/bloom.cpp
index cef74a3a54..c1e7aeb3bf 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -4,9 +4,10 @@
#include "bloom.h"
-#include "core.h"
+#include "core/transaction.h"
#include "script/script.h"
#include "script/standard.h"
+#include "streams.h"
#include <math.h>
#include <stdlib.h>
diff --git a/src/chain.h b/src/chain.h
index 07e72d3498..7c5603dafc 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -6,7 +6,7 @@
#ifndef H_BITCOIN_CHAIN
#define H_BITCOIN_CHAIN
-#include "core.h"
+#include "core/block.h"
#include "pow.h"
#include "tinyformat.h"
#include "uint256.h"
diff --git a/src/chainparams.h b/src/chainparams.h
index 6eba970ccc..9279edd6c0 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_CHAIN_PARAMS_H
#define BITCOIN_CHAIN_PARAMS_H
-#include "core.h"
#include "chainparamsbase.h"
#include "checkpoints.h"
+#include "core/block.h"
#include "protocol.h"
#include "uint256.h"
diff --git a/src/coincontrol.h b/src/coincontrol.h
index 033092c019..c8f12d92de 100644
--- a/src/coincontrol.h
+++ b/src/coincontrol.h
@@ -5,7 +5,7 @@
#ifndef COINCONTROL_H
#define COINCONTROL_H
-#include "core.h"
+#include "core/transaction.h"
/** Coin Control Features. */
class CCoinControl
diff --git a/src/coins.h b/src/coins.h
index b8f1e5bcc5..ee9051562b 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -6,9 +6,10 @@
#ifndef BITCOIN_COINS_H
#define BITCOIN_COINS_H
-#include "core.h"
+#include "compressor.h"
#include "serialize.h"
#include "uint256.h"
+#include "undo.h"
#include <assert.h>
#include <stdint.h>
diff --git a/src/script/compressor.cpp b/src/compressor.cpp
index af1acf48db..806175dd3e 100644
--- a/src/script/compressor.cpp
+++ b/src/compressor.cpp
@@ -5,6 +5,7 @@
#include "compressor.h"
+#include "hash.h"
#include "key.h"
#include "script/standard.h"
@@ -128,3 +129,57 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
}
return false;
}
+
+// Amount compression:
+// * If the amount is 0, output 0
+// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
+// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
+// * call the result n
+// * output 1 + 10*(9*n + d - 1) + e
+// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
+// (this is decodable, as d is in [1-9] and e is in [0-9])
+
+uint64_t CTxOutCompressor::CompressAmount(uint64_t n)
+{
+ if (n == 0)
+ return 0;
+ int e = 0;
+ while (((n % 10) == 0) && e < 9) {
+ n /= 10;
+ e++;
+ }
+ if (e < 9) {
+ int d = (n % 10);
+ assert(d >= 1 && d <= 9);
+ n /= 10;
+ return 1 + (n*9 + d - 1)*10 + e;
+ } else {
+ return 1 + (n - 1)*10 + 9;
+ }
+}
+
+uint64_t CTxOutCompressor::DecompressAmount(uint64_t x)
+{
+ // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
+ if (x == 0)
+ return 0;
+ x--;
+ // x = 10*(9*n + d - 1) + e
+ int e = x % 10;
+ x /= 10;
+ uint64_t n = 0;
+ if (e < 9) {
+ // x = 9*n + d - 1
+ int d = (x % 9) + 1;
+ x /= 9;
+ // x = n
+ n = x*10 + d;
+ } else {
+ n = x+1;
+ }
+ while (e) {
+ n *= 10;
+ e--;
+ }
+ return n;
+}
diff --git a/src/script/compressor.h b/src/compressor.h
index 154e0b2662..a612c3a883 100644
--- a/src/script/compressor.h
+++ b/src/compressor.h
@@ -3,9 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef H_BITCOIN_SCRIPT_COMPRESSOR
-#define H_BITCOIN_SCRIPT_COMPRESSOR
+#ifndef H_BITCOIN_COMPRESSOR
+#define H_BITCOIN_COMPRESSOR
+#include "core/transaction.h"
#include "script/script.h"
#include "serialize.h"
@@ -86,4 +87,33 @@ public:
}
};
-#endif // H_BITCOIN_SCRIPT_COMPRESSOR
+/** wrapper for CTxOut that provides a more compact serialization */
+class CTxOutCompressor
+{
+private:
+ CTxOut &txout;
+
+public:
+ static uint64_t CompressAmount(uint64_t nAmount);
+ static uint64_t DecompressAmount(uint64_t nAmount);
+
+ CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (!ser_action.ForRead()) {
+ uint64_t nVal = CompressAmount(txout.nValue);
+ READWRITE(VARINT(nVal));
+ } else {
+ uint64_t nVal = 0;
+ READWRITE(VARINT(nVal));
+ txout.nValue = DecompressAmount(nVal);
+ }
+ CScriptCompressor cscript(REF(txout.scriptPubKey));
+ READWRITE(cscript);
+ }
+};
+
+#endif // H_BITCOIN_COMPRESSOR
diff --git a/src/core.cpp b/src/core.cpp
deleted file mode 100644
index 73e6de88e1..0000000000
--- a/src/core.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "core.h"
-
-#include "hash.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
-
-std::string COutPoint::ToString() const
-{
- return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
-}
-
-CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
-{
- prevout = prevoutIn;
- scriptSig = scriptSigIn;
- nSequence = nSequenceIn;
-}
-
-CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn)
-{
- prevout = COutPoint(hashPrevTx, nOut);
- scriptSig = scriptSigIn;
- nSequence = nSequenceIn;
-}
-
-std::string CTxIn::ToString() const
-{
- std::string str;
- str += "CTxIn(";
- str += prevout.ToString();
- if (prevout.IsNull())
- str += strprintf(", coinbase %s", HexStr(scriptSig));
- else
- str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
- if (nSequence != std::numeric_limits<unsigned int>::max())
- str += strprintf(", nSequence=%u", nSequence);
- str += ")";
- return str;
-}
-
-CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
-{
- nValue = nValueIn;
- scriptPubKey = scriptPubKeyIn;
-}
-
-uint256 CTxOut::GetHash() const
-{
- return SerializeHash(*this);
-}
-
-std::string CTxOut::ToString() const
-{
- return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
-}
-
-CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
-{
- if (nSize > 0)
- nSatoshisPerK = nFeePaid*1000/nSize;
- else
- nSatoshisPerK = 0;
-}
-
-CAmount CFeeRate::GetFee(size_t nSize) const
-{
- CAmount nFee = nSatoshisPerK*nSize / 1000;
-
- if (nFee == 0 && nSatoshisPerK > 0)
- nFee = nSatoshisPerK;
-
- return nFee;
-}
-
-std::string CFeeRate::ToString() const
-{
- return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN);
-}
-
-CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
-CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
-
-uint256 CMutableTransaction::GetHash() const
-{
- return SerializeHash(*this);
-}
-
-void CTransaction::UpdateHash() const
-{
- *const_cast<uint256*>(&hash) = SerializeHash(*this);
-}
-
-CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
-
-CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
- UpdateHash();
-}
-
-CTransaction& CTransaction::operator=(const CTransaction &tx) {
- *const_cast<int*>(&nVersion) = tx.nVersion;
- *const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
- *const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
- *const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
- *const_cast<uint256*>(&hash) = tx.hash;
- return *this;
-}
-
-CAmount CTransaction::GetValueOut() const
-{
- CAmount nValueOut = 0;
- for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it)
- {
- nValueOut += it->nValue;
- if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
- }
- return nValueOut;
-}
-
-double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
-{
- nTxSize = CalculateModifiedSize(nTxSize);
- if (nTxSize == 0) return 0.0;
-
- return dPriorityInputs / nTxSize;
-}
-
-unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
-{
- // In order to avoid disincentivizing cleaning up the UTXO set we don't count
- // the constant overhead for each txin and up to 110 bytes of scriptSig (which
- // is enough to cover a compressed pubkey p2sh redemption) for priority.
- // Providing any more cleanup incentive than making additional inputs free would
- // risk encouraging people to create junk outputs to redeem later.
- if (nTxSize == 0)
- nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
- for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
- {
- unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
- if (nTxSize > offset)
- nTxSize -= offset;
- }
- return nTxSize;
-}
-
-std::string CTransaction::ToString() const
-{
- std::string str;
- str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
- GetHash().ToString().substr(0,10),
- nVersion,
- vin.size(),
- vout.size(),
- nLockTime);
- for (unsigned int i = 0; i < vin.size(); i++)
- str += " " + vin[i].ToString() + "\n";
- for (unsigned int i = 0; i < vout.size(); i++)
- str += " " + vout[i].ToString() + "\n";
- return str;
-}
-
-// Amount compression:
-// * If the amount is 0, output 0
-// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
-// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
-// * call the result n
-// * output 1 + 10*(9*n + d - 1) + e
-// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
-// (this is decodable, as d is in [1-9] and e is in [0-9])
-
-uint64_t CTxOutCompressor::CompressAmount(uint64_t n)
-{
- if (n == 0)
- return 0;
- int e = 0;
- while (((n % 10) == 0) && e < 9) {
- n /= 10;
- e++;
- }
- if (e < 9) {
- int d = (n % 10);
- assert(d >= 1 && d <= 9);
- n /= 10;
- return 1 + (n*9 + d - 1)*10 + e;
- } else {
- return 1 + (n - 1)*10 + 9;
- }
-}
-
-uint64_t CTxOutCompressor::DecompressAmount(uint64_t x)
-{
- // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
- if (x == 0)
- return 0;
- x--;
- // x = 10*(9*n + d - 1) + e
- int e = x % 10;
- x /= 10;
- uint64_t n = 0;
- if (e < 9) {
- // x = 9*n + d - 1
- int d = (x % 9) + 1;
- x /= 9;
- // x = n
- n = x*10 + d;
- } else {
- n = x+1;
- }
- while (e) {
- n *= 10;
- e--;
- }
- return n;
-}
-
-uint256 CBlockHeader::GetHash() const
-{
- return Hash(BEGIN(nVersion), END(nNonce));
-}
-
-uint256 CBlock::BuildMerkleTree(bool* fMutated) const
-{
- /* WARNING! If you're reading this because you're learning about crypto
- and/or designing a new system that will use merkle trees, keep in mind
- that the following merkle tree algorithm has a serious flaw related to
- duplicate txids, resulting in a vulnerability (CVE-2012-2459).
-
- The reason is that if the number of hashes in the list at a given time
- is odd, the last one is duplicated before computing the next level (which
- is unusual in Merkle trees). This results in certain sequences of
- transactions leading to the same merkle root. For example, these two
- trees:
-
- A A
- / \ / \
- B C B C
- / \ | / \ / \
- D E F D E F F
- / \ / \ / \ / \ / \ / \ / \
- 1 2 3 4 5 6 1 2 3 4 5 6 5 6
-
- for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
- 6 are repeated) result in the same root hash A (because the hash of both
- of (F) and (F,F) is C).
-
- The vulnerability results from being able to send a block with such a
- transaction list, with the same merkle root, and the same block hash as
- the original without duplication, resulting in failed validation. If the
- receiving node proceeds to mark that block as permanently invalid
- however, it will fail to accept further unmodified (and thus potentially
- valid) versions of the same block. We defend against this by detecting
- the case where we would hash two identical hashes at the end of the list
- together, and treating that identically to the block having an invalid
- merkle root. Assuming no double-SHA256 collisions, this will detect all
- known ways of changing the transactions without affecting the merkle
- root.
- */
- vMerkleTree.clear();
- vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
- for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it)
- vMerkleTree.push_back(it->GetHash());
- int j = 0;
- bool mutated = false;
- for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
- {
- for (int i = 0; i < nSize; i += 2)
- {
- int i2 = std::min(i+1, nSize-1);
- if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {
- // Two identical hashes at the end of the list at a particular level.
- mutated = true;
- }
- vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
- BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
- }
- j += nSize;
- }
- if (fMutated) {
- *fMutated = mutated;
- }
- return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
-}
-
-std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
-{
- if (vMerkleTree.empty())
- BuildMerkleTree();
- std::vector<uint256> vMerkleBranch;
- int j = 0;
- for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
- {
- int i = std::min(nIndex^1, nSize-1);
- vMerkleBranch.push_back(vMerkleTree[j+i]);
- nIndex >>= 1;
- j += nSize;
- }
- return vMerkleBranch;
-}
-
-uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
-{
- if (nIndex == -1)
- return 0;
- for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
- {
- if (nIndex & 1)
- hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
- else
- hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
- nIndex >>= 1;
- }
- return hash;
-}
-
-std::string CBlock::ToString() const
-{
- std::stringstream s;
- s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
- GetHash().ToString(),
- nVersion,
- hashPrevBlock.ToString(),
- hashMerkleRoot.ToString(),
- nTime, nBits, nNonce,
- vtx.size());
- for (unsigned int i = 0; i < vtx.size(); i++)
- {
- s << " " << vtx[i].ToString() << "\n";
- }
- s << " vMerkleTree: ";
- for (unsigned int i = 0; i < vMerkleTree.size(); i++)
- s << " " << vMerkleTree[i].ToString();
- s << "\n";
- return s.str();
-}
diff --git a/src/core.h b/src/core.h
deleted file mode 100644
index a024dad740..0000000000
--- a/src/core.h
+++ /dev/null
@@ -1,566 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_CORE_H
-#define BITCOIN_CORE_H
-
-#include "amount.h"
-#include "script/compressor.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "uint256.h"
-
-#include <stdint.h>
-
-class CTransaction;
-
-static const int64_t COIN = 100000000;
-static const int64_t CENT = 1000000;
-
-/** No amount larger than this (in satoshi) is valid */
-static const CAmount MAX_MONEY = 21000000 * COIN;
-inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
-
-/** An outpoint - a combination of a transaction hash and an index n into its vout */
-class COutPoint
-{
-public:
- uint256 hash;
- uint32_t n;
-
- COutPoint() { SetNull(); }
- COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(FLATDATA(*this));
- }
-
- void SetNull() { hash = 0; n = (uint32_t) -1; }
- bool IsNull() const { return (hash == 0 && n == (uint32_t) -1); }
-
- friend bool operator<(const COutPoint& a, const COutPoint& b)
- {
- return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
- }
-
- friend bool operator==(const COutPoint& a, const COutPoint& b)
- {
- return (a.hash == b.hash && a.n == b.n);
- }
-
- friend bool operator!=(const COutPoint& a, const COutPoint& b)
- {
- return !(a == b);
- }
-
- std::string ToString() const;
-};
-
-/** An input of a transaction. It contains the location of the previous
- * transaction's output that it claims and a signature that matches the
- * output's public key.
- */
-class CTxIn
-{
-public:
- COutPoint prevout;
- CScript scriptSig;
- uint32_t nSequence;
-
- CTxIn()
- {
- nSequence = std::numeric_limits<unsigned int>::max();
- }
-
- explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max());
- CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<uint32_t>::max());
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(prevout);
- READWRITE(scriptSig);
- READWRITE(nSequence);
- }
-
- bool IsFinal() const
- {
- return (nSequence == std::numeric_limits<uint32_t>::max());
- }
-
- friend bool operator==(const CTxIn& a, const CTxIn& b)
- {
- return (a.prevout == b.prevout &&
- a.scriptSig == b.scriptSig &&
- a.nSequence == b.nSequence);
- }
-
- friend bool operator!=(const CTxIn& a, const CTxIn& b)
- {
- return !(a == b);
- }
-
- std::string ToString() const;
-};
-
-
-
-/** Type-safe wrapper class to for fee rates
- * (how much to pay based on transaction size)
- */
-class CFeeRate
-{
-private:
- CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
-public:
- CFeeRate() : nSatoshisPerK(0) { }
- explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
- CFeeRate(const CAmount& nFeePaid, size_t nSize);
- CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
-
- CAmount GetFee(size_t size) const; // unit returned is satoshis
- CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes
-
- 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; }
- 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; }
- std::string ToString() const;
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(nSatoshisPerK);
- }
-};
-
-
-/** An output of a transaction. It contains the public key that the next input
- * must be able to sign with to claim it.
- */
-class CTxOut
-{
-public:
- CAmount nValue;
- CScript scriptPubKey;
-
- CTxOut()
- {
- SetNull();
- }
-
- CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(nValue);
- READWRITE(scriptPubKey);
- }
-
- void SetNull()
- {
- nValue = -1;
- scriptPubKey.clear();
- }
-
- bool IsNull() const
- {
- return (nValue == -1);
- }
-
- uint256 GetHash() const;
-
- bool IsDust(CFeeRate minRelayTxFee) const
- {
- // "Dust" is defined in terms of CTransaction::minRelayTxFee,
- // which has units satoshis-per-kilobyte.
- // If you'd pay more than 1/3 in fees
- // to spend something, then we consider it dust.
- // A typical txout is 34 bytes big, and will
- // need a CTxIn of at least 148 bytes to spend:
- // so dust is a txout less than 546 satoshis
- // with default minRelayTxFee.
- size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
- return (nValue < 3*minRelayTxFee.GetFee(nSize));
- }
-
- friend bool operator==(const CTxOut& a, const CTxOut& b)
- {
- return (a.nValue == b.nValue &&
- a.scriptPubKey == b.scriptPubKey);
- }
-
- friend bool operator!=(const CTxOut& a, const CTxOut& b)
- {
- return !(a == b);
- }
-
- std::string ToString() const;
-};
-
-
-struct CMutableTransaction;
-
-/** The basic transaction that is broadcasted on the network and contained in
- * blocks. A transaction can contain multiple inputs and outputs.
- */
-class CTransaction
-{
-private:
- /** Memory only. */
- const uint256 hash;
- void UpdateHash() const;
-
-public:
- static const int32_t CURRENT_VERSION=1;
-
- // The local variables are made const to prevent unintended modification
- // without updating the cached hash value. However, CTransaction is not
- // actually immutable; deserialization and assignment are implemented,
- // and bypass the constness. This is safe, as they update the entire
- // structure, including the hash.
- const int32_t nVersion;
- const std::vector<CTxIn> vin;
- const std::vector<CTxOut> vout;
- const uint32_t nLockTime;
-
- /** Construct a CTransaction that qualifies as IsNull() */
- CTransaction();
-
- /** Convert a CMutableTransaction into a CTransaction. */
- CTransaction(const CMutableTransaction &tx);
-
- CTransaction& operator=(const CTransaction& tx);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*const_cast<int32_t*>(&this->nVersion));
- nVersion = this->nVersion;
- READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
- READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
- READWRITE(*const_cast<uint32_t*>(&nLockTime));
- if (ser_action.ForRead())
- UpdateHash();
- }
-
- bool IsNull() const {
- return vin.empty() && vout.empty();
- }
-
- const uint256& GetHash() const {
- return hash;
- }
-
- // Return sum of txouts.
- CAmount GetValueOut() const;
- // GetValueIn() is a method on CCoinsViewCache, because
- // inputs must be known to compute value in.
-
- // Compute priority, given priority of inputs and (optionally) tx size
- double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
-
- // Compute modified tx size for priority calculation (optionally given tx size)
- unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
-
- bool IsCoinBase() const
- {
- return (vin.size() == 1 && vin[0].prevout.IsNull());
- }
-
- friend bool operator==(const CTransaction& a, const CTransaction& b)
- {
- return a.hash == b.hash;
- }
-
- friend bool operator!=(const CTransaction& a, const CTransaction& b)
- {
- return a.hash != b.hash;
- }
-
- std::string ToString() const;
-};
-
-/** A mutable version of CTransaction. */
-struct CMutableTransaction
-{
- int32_t nVersion;
- std::vector<CTxIn> vin;
- std::vector<CTxOut> vout;
- uint32_t nLockTime;
-
- CMutableTransaction();
- CMutableTransaction(const CTransaction& tx);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(vin);
- READWRITE(vout);
- READWRITE(nLockTime);
- }
-
- /** Compute the hash of this CMutableTransaction. This is computed on the
- * fly, as opposed to GetHash() in CTransaction, which uses a cached result.
- */
- uint256 GetHash() const;
-};
-
-/** wrapper for CTxOut that provides a more compact serialization */
-class CTxOutCompressor
-{
-private:
- CTxOut &txout;
-
-public:
- static uint64_t CompressAmount(uint64_t nAmount);
- static uint64_t DecompressAmount(uint64_t nAmount);
-
- CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!ser_action.ForRead()) {
- uint64_t nVal = CompressAmount(txout.nValue);
- READWRITE(VARINT(nVal));
- } else {
- uint64_t nVal = 0;
- READWRITE(VARINT(nVal));
- txout.nValue = DecompressAmount(nVal);
- }
- CScriptCompressor cscript(REF(txout.scriptPubKey));
- READWRITE(cscript);
- }
-};
-
-/** Undo information for a CTxIn
- *
- * Contains the prevout's CTxOut being spent, and if this was the
- * last output of the affected transaction, its metadata as well
- * (coinbase or not, height, transaction version)
- */
-class CTxInUndo
-{
-public:
- CTxOut txout; // the txout data before being spent
- bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase
- unsigned int nHeight; // if the outpoint was the last unspent: its height
- int nVersion; // if the outpoint was the last unspent: its version
-
- CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {}
- CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { }
-
- unsigned int GetSerializeSize(int nType, int nVersion) const {
- return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) +
- (nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) +
- ::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion);
- }
-
- template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersion) const {
- ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion);
- if (nHeight > 0)
- ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
- ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion);
- }
-
- template<typename Stream>
- void Unserialize(Stream &s, int nType, int nVersion) {
- unsigned int nCode = 0;
- ::Unserialize(s, VARINT(nCode), nType, nVersion);
- nHeight = nCode / 2;
- fCoinBase = nCode & 1;
- if (nHeight > 0)
- ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
- ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion);
- }
-};
-
-/** Undo information for a CTransaction */
-class CTxUndo
-{
-public:
- // undo information for all txins
- std::vector<CTxInUndo> vprevout;
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(vprevout);
- }
-};
-
-
-/** Nodes collect new transactions into a block, hash them into a hash tree,
- * and scan through nonce values to make the block's hash satisfy proof-of-work
- * requirements. When they solve the proof-of-work, they broadcast the block
- * to everyone and the block is added to the block chain. The first transaction
- * in the block is a special one that creates a new coin owned by the creator
- * of the block.
- */
-class CBlockHeader
-{
-public:
- // header
- static const int32_t CURRENT_VERSION=2;
- int32_t nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- uint32_t nTime;
- uint32_t nBits;
- uint32_t nNonce;
-
- CBlockHeader()
- {
- SetNull();
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(hashPrevBlock);
- READWRITE(hashMerkleRoot);
- READWRITE(nTime);
- READWRITE(nBits);
- READWRITE(nNonce);
- }
-
- void SetNull()
- {
- nVersion = CBlockHeader::CURRENT_VERSION;
- hashPrevBlock = 0;
- hashMerkleRoot = 0;
- nTime = 0;
- nBits = 0;
- nNonce = 0;
- }
-
- bool IsNull() const
- {
- return (nBits == 0);
- }
-
- uint256 GetHash() const;
-
- int64_t GetBlockTime() const
- {
- return (int64_t)nTime;
- }
-};
-
-
-class CBlock : public CBlockHeader
-{
-public:
- // network and disk
- std::vector<CTransaction> vtx;
-
- // memory only
- mutable std::vector<uint256> vMerkleTree;
-
- CBlock()
- {
- SetNull();
- }
-
- CBlock(const CBlockHeader &header)
- {
- SetNull();
- *((CBlockHeader*)this) = header;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*(CBlockHeader*)this);
- READWRITE(vtx);
- }
-
- void SetNull()
- {
- CBlockHeader::SetNull();
- vtx.clear();
- vMerkleTree.clear();
- }
-
- CBlockHeader GetBlockHeader() const
- {
- CBlockHeader block;
- block.nVersion = nVersion;
- block.hashPrevBlock = hashPrevBlock;
- block.hashMerkleRoot = hashMerkleRoot;
- block.nTime = nTime;
- block.nBits = nBits;
- block.nNonce = nNonce;
- return block;
- }
-
- // Build the in-memory merkle tree for this block and return the merkle root.
- // If non-NULL, *mutated is set to whether mutation was detected in the merkle
- // tree (a duplication of transactions in the block leading to an identical
- // merkle root).
- uint256 BuildMerkleTree(bool* mutated = NULL) const;
-
- std::vector<uint256> GetMerkleBranch(int nIndex) const;
- static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
- std::string ToString() const;
-};
-
-
-/** Describes a place in the block chain to another node such that if the
- * other node doesn't have the same branch, it can find a recent common trunk.
- * The further back it is, the further before the fork it may be.
- */
-struct CBlockLocator
-{
- std::vector<uint256> vHave;
-
- CBlockLocator() {}
-
- CBlockLocator(const std::vector<uint256>& vHaveIn)
- {
- vHave = vHaveIn;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- READWRITE(vHave);
- }
-
- void SetNull()
- {
- vHave.clear();
- }
-
- bool IsNull()
- {
- return vHave.empty();
- }
-};
-
-#endif // BITCOIN_CORE_H
diff --git a/src/core/block.cpp b/src/core/block.cpp
new file mode 100644
index 0000000000..2010d44dac
--- /dev/null
+++ b/src/core/block.cpp
@@ -0,0 +1,130 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "core/block.h"
+
+#include "hash.h"
+#include "tinyformat.h"
+#include "utilstrencodings.h"
+
+uint256 CBlockHeader::GetHash() const
+{
+ return Hash(BEGIN(nVersion), END(nNonce));
+}
+
+uint256 CBlock::BuildMerkleTree(bool* fMutated) const
+{
+ /* WARNING! If you're reading this because you're learning about crypto
+ and/or designing a new system that will use merkle trees, keep in mind
+ that the following merkle tree algorithm has a serious flaw related to
+ duplicate txids, resulting in a vulnerability (CVE-2012-2459).
+
+ The reason is that if the number of hashes in the list at a given time
+ is odd, the last one is duplicated before computing the next level (which
+ is unusual in Merkle trees). This results in certain sequences of
+ transactions leading to the same merkle root. For example, these two
+ trees:
+
+ A A
+ / \ / \
+ B C B C
+ / \ | / \ / \
+ D E F D E F F
+ / \ / \ / \ / \ / \ / \ / \
+ 1 2 3 4 5 6 1 2 3 4 5 6 5 6
+
+ for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
+ 6 are repeated) result in the same root hash A (because the hash of both
+ of (F) and (F,F) is C).
+
+ The vulnerability results from being able to send a block with such a
+ transaction list, with the same merkle root, and the same block hash as
+ the original without duplication, resulting in failed validation. If the
+ receiving node proceeds to mark that block as permanently invalid
+ however, it will fail to accept further unmodified (and thus potentially
+ valid) versions of the same block. We defend against this by detecting
+ the case where we would hash two identical hashes at the end of the list
+ together, and treating that identically to the block having an invalid
+ merkle root. Assuming no double-SHA256 collisions, this will detect all
+ known ways of changing the transactions without affecting the merkle
+ root.
+ */
+ vMerkleTree.clear();
+ vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
+ for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it)
+ vMerkleTree.push_back(it->GetHash());
+ int j = 0;
+ bool mutated = false;
+ for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
+ {
+ for (int i = 0; i < nSize; i += 2)
+ {
+ int i2 = std::min(i+1, nSize-1);
+ if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {
+ // Two identical hashes at the end of the list at a particular level.
+ mutated = true;
+ }
+ vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
+ BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
+ }
+ j += nSize;
+ }
+ if (fMutated) {
+ *fMutated = mutated;
+ }
+ return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
+}
+
+std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
+{
+ if (vMerkleTree.empty())
+ BuildMerkleTree();
+ std::vector<uint256> vMerkleBranch;
+ int j = 0;
+ for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
+ {
+ int i = std::min(nIndex^1, nSize-1);
+ vMerkleBranch.push_back(vMerkleTree[j+i]);
+ nIndex >>= 1;
+ j += nSize;
+ }
+ return vMerkleBranch;
+}
+
+uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
+{
+ if (nIndex == -1)
+ return 0;
+ for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
+ {
+ if (nIndex & 1)
+ hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
+ else
+ hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
+ nIndex >>= 1;
+ }
+ return hash;
+}
+
+std::string CBlock::ToString() const
+{
+ std::stringstream s;
+ s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
+ GetHash().ToString(),
+ nVersion,
+ hashPrevBlock.ToString(),
+ hashMerkleRoot.ToString(),
+ nTime, nBits, nNonce,
+ vtx.size());
+ for (unsigned int i = 0; i < vtx.size(); i++)
+ {
+ s << " " << vtx[i].ToString() << "\n";
+ }
+ s << " vMerkleTree: ";
+ for (unsigned int i = 0; i < vMerkleTree.size(); i++)
+ s << " " << vMerkleTree[i].ToString();
+ s << "\n";
+ return s.str();
+}
diff --git a/src/core/block.h b/src/core/block.h
new file mode 100644
index 0000000000..f1eb7a844f
--- /dev/null
+++ b/src/core/block.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_CORE_BLOCK
+#define H_BITCOIN_CORE_BLOCK
+
+#include "core/transaction.h"
+#include "serialize.h"
+#include "uint256.h"
+
+/** Nodes collect new transactions into a block, hash them into a hash tree,
+ * and scan through nonce values to make the block's hash satisfy proof-of-work
+ * requirements. When they solve the proof-of-work, they broadcast the block
+ * to everyone and the block is added to the block chain. The first transaction
+ * in the block is a special one that creates a new coin owned by the creator
+ * of the block.
+ */
+class CBlockHeader
+{
+public:
+ // header
+ static const int32_t CURRENT_VERSION=2;
+ int32_t nVersion;
+ uint256 hashPrevBlock;
+ uint256 hashMerkleRoot;
+ uint32_t nTime;
+ uint32_t nBits;
+ uint32_t nNonce;
+
+ CBlockHeader()
+ {
+ SetNull();
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(hashPrevBlock);
+ READWRITE(hashMerkleRoot);
+ READWRITE(nTime);
+ READWRITE(nBits);
+ READWRITE(nNonce);
+ }
+
+ void SetNull()
+ {
+ nVersion = CBlockHeader::CURRENT_VERSION;
+ hashPrevBlock = 0;
+ hashMerkleRoot = 0;
+ nTime = 0;
+ nBits = 0;
+ nNonce = 0;
+ }
+
+ bool IsNull() const
+ {
+ return (nBits == 0);
+ }
+
+ uint256 GetHash() const;
+
+ int64_t GetBlockTime() const
+ {
+ return (int64_t)nTime;
+ }
+};
+
+
+class CBlock : public CBlockHeader
+{
+public:
+ // network and disk
+ std::vector<CTransaction> vtx;
+
+ // memory only
+ mutable std::vector<uint256> vMerkleTree;
+
+ CBlock()
+ {
+ SetNull();
+ }
+
+ CBlock(const CBlockHeader &header)
+ {
+ SetNull();
+ *((CBlockHeader*)this) = header;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(*(CBlockHeader*)this);
+ READWRITE(vtx);
+ }
+
+ void SetNull()
+ {
+ CBlockHeader::SetNull();
+ vtx.clear();
+ vMerkleTree.clear();
+ }
+
+ CBlockHeader GetBlockHeader() const
+ {
+ CBlockHeader block;
+ block.nVersion = nVersion;
+ block.hashPrevBlock = hashPrevBlock;
+ block.hashMerkleRoot = hashMerkleRoot;
+ block.nTime = nTime;
+ block.nBits = nBits;
+ block.nNonce = nNonce;
+ return block;
+ }
+
+ // Build the in-memory merkle tree for this block and return the merkle root.
+ // If non-NULL, *mutated is set to whether mutation was detected in the merkle
+ // tree (a duplication of transactions in the block leading to an identical
+ // merkle root).
+ uint256 BuildMerkleTree(bool* mutated = NULL) const;
+
+ std::vector<uint256> GetMerkleBranch(int nIndex) const;
+ static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
+ std::string ToString() const;
+};
+
+
+/** Describes a place in the block chain to another node such that if the
+ * other node doesn't have the same branch, it can find a recent common trunk.
+ * The further back it is, the further before the fork it may be.
+ */
+struct CBlockLocator
+{
+ std::vector<uint256> vHave;
+
+ CBlockLocator() {}
+
+ CBlockLocator(const std::vector<uint256>& vHaveIn)
+ {
+ vHave = vHaveIn;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vHave);
+ }
+
+ void SetNull()
+ {
+ vHave.clear();
+ }
+
+ bool IsNull()
+ {
+ return vHave.empty();
+ }
+};
+
+#endif // H_BITCOIN_CORE_BLOCK
diff --git a/src/core/transaction.cpp b/src/core/transaction.cpp
new file mode 100644
index 0000000000..f835bafb9f
--- /dev/null
+++ b/src/core/transaction.cpp
@@ -0,0 +1,142 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "core/transaction.h"
+
+#include "hash.h"
+#include "tinyformat.h"
+#include "utilstrencodings.h"
+
+std::string COutPoint::ToString() const
+{
+ return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
+}
+
+CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
+{
+ prevout = prevoutIn;
+ scriptSig = scriptSigIn;
+ nSequence = nSequenceIn;
+}
+
+CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn)
+{
+ prevout = COutPoint(hashPrevTx, nOut);
+ scriptSig = scriptSigIn;
+ nSequence = nSequenceIn;
+}
+
+std::string CTxIn::ToString() const
+{
+ std::string str;
+ str += "CTxIn(";
+ str += prevout.ToString();
+ if (prevout.IsNull())
+ str += strprintf(", coinbase %s", HexStr(scriptSig));
+ else
+ str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
+ if (nSequence != std::numeric_limits<unsigned int>::max())
+ str += strprintf(", nSequence=%u", nSequence);
+ str += ")";
+ return str;
+}
+
+CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
+{
+ nValue = nValueIn;
+ scriptPubKey = scriptPubKeyIn;
+}
+
+uint256 CTxOut::GetHash() const
+{
+ return SerializeHash(*this);
+}
+
+std::string CTxOut::ToString() const
+{
+ return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
+}
+
+CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
+
+uint256 CMutableTransaction::GetHash() const
+{
+ return SerializeHash(*this);
+}
+
+void CTransaction::UpdateHash() const
+{
+ *const_cast<uint256*>(&hash) = SerializeHash(*this);
+}
+
+CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
+
+CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
+ UpdateHash();
+}
+
+CTransaction& CTransaction::operator=(const CTransaction &tx) {
+ *const_cast<int*>(&nVersion) = tx.nVersion;
+ *const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
+ *const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
+ *const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
+ *const_cast<uint256*>(&hash) = tx.hash;
+ return *this;
+}
+
+CAmount CTransaction::GetValueOut() const
+{
+ CAmount nValueOut = 0;
+ for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it)
+ {
+ nValueOut += it->nValue;
+ if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
+ throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
+ }
+ return nValueOut;
+}
+
+double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
+{
+ nTxSize = CalculateModifiedSize(nTxSize);
+ if (nTxSize == 0) return 0.0;
+
+ return dPriorityInputs / nTxSize;
+}
+
+unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
+{
+ // In order to avoid disincentivizing cleaning up the UTXO set we don't count
+ // the constant overhead for each txin and up to 110 bytes of scriptSig (which
+ // is enough to cover a compressed pubkey p2sh redemption) for priority.
+ // Providing any more cleanup incentive than making additional inputs free would
+ // risk encouraging people to create junk outputs to redeem later.
+ if (nTxSize == 0)
+ nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+ for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
+ {
+ unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
+ if (nTxSize > offset)
+ nTxSize -= offset;
+ }
+ return nTxSize;
+}
+
+std::string CTransaction::ToString() const
+{
+ std::string str;
+ str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
+ GetHash().ToString().substr(0,10),
+ nVersion,
+ vin.size(),
+ vout.size(),
+ nLockTime);
+ for (unsigned int i = 0; i < vin.size(); i++)
+ str += " " + vin[i].ToString() + "\n";
+ for (unsigned int i = 0; i < vout.size(); i++)
+ str += " " + vout[i].ToString() + "\n";
+ return str;
+}
diff --git a/src/core/transaction.h b/src/core/transaction.h
new file mode 100644
index 0000000000..c21558cfeb
--- /dev/null
+++ b/src/core/transaction.h
@@ -0,0 +1,276 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_CORE_TRANSACTION
+#define H_BITCOIN_CORE_TRANSACTION
+
+#include "amount.h"
+#include "script/script.h"
+#include "serialize.h"
+#include "uint256.h"
+
+/** An outpoint - a combination of a transaction hash and an index n into its vout */
+class COutPoint
+{
+public:
+ uint256 hash;
+ uint32_t n;
+
+ COutPoint() { SetNull(); }
+ COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(FLATDATA(*this));
+ }
+
+ void SetNull() { hash = 0; n = (uint32_t) -1; }
+ bool IsNull() const { return (hash == 0 && n == (uint32_t) -1); }
+
+ friend bool operator<(const COutPoint& a, const COutPoint& b)
+ {
+ return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
+ }
+
+ friend bool operator==(const COutPoint& a, const COutPoint& b)
+ {
+ return (a.hash == b.hash && a.n == b.n);
+ }
+
+ friend bool operator!=(const COutPoint& a, const COutPoint& b)
+ {
+ return !(a == b);
+ }
+
+ std::string ToString() const;
+};
+
+/** An input of a transaction. It contains the location of the previous
+ * transaction's output that it claims and a signature that matches the
+ * output's public key.
+ */
+class CTxIn
+{
+public:
+ COutPoint prevout;
+ CScript scriptSig;
+ uint32_t nSequence;
+
+ CTxIn()
+ {
+ nSequence = std::numeric_limits<unsigned int>::max();
+ }
+
+ explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max());
+ CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<uint32_t>::max());
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(prevout);
+ READWRITE(scriptSig);
+ READWRITE(nSequence);
+ }
+
+ bool IsFinal() const
+ {
+ return (nSequence == std::numeric_limits<uint32_t>::max());
+ }
+
+ friend bool operator==(const CTxIn& a, const CTxIn& b)
+ {
+ return (a.prevout == b.prevout &&
+ a.scriptSig == b.scriptSig &&
+ a.nSequence == b.nSequence);
+ }
+
+ friend bool operator!=(const CTxIn& a, const CTxIn& b)
+ {
+ return !(a == b);
+ }
+
+ std::string ToString() const;
+};
+
+/** An output of a transaction. It contains the public key that the next input
+ * must be able to sign with to claim it.
+ */
+class CTxOut
+{
+public:
+ CAmount nValue;
+ CScript scriptPubKey;
+
+ CTxOut()
+ {
+ SetNull();
+ }
+
+ CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(nValue);
+ READWRITE(scriptPubKey);
+ }
+
+ void SetNull()
+ {
+ nValue = -1;
+ scriptPubKey.clear();
+ }
+
+ bool IsNull() const
+ {
+ return (nValue == -1);
+ }
+
+ uint256 GetHash() const;
+
+ bool IsDust(CFeeRate minRelayTxFee) const
+ {
+ // "Dust" is defined in terms of CTransaction::minRelayTxFee,
+ // which has units satoshis-per-kilobyte.
+ // If you'd pay more than 1/3 in fees
+ // to spend something, then we consider it dust.
+ // A typical txout is 34 bytes big, and will
+ // need a CTxIn of at least 148 bytes to spend:
+ // so dust is a txout less than 546 satoshis
+ // with default minRelayTxFee.
+ size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
+ return (nValue < 3*minRelayTxFee.GetFee(nSize));
+ }
+
+ friend bool operator==(const CTxOut& a, const CTxOut& b)
+ {
+ return (a.nValue == b.nValue &&
+ a.scriptPubKey == b.scriptPubKey);
+ }
+
+ friend bool operator!=(const CTxOut& a, const CTxOut& b)
+ {
+ return !(a == b);
+ }
+
+ std::string ToString() const;
+};
+
+struct CMutableTransaction;
+
+/** The basic transaction that is broadcasted on the network and contained in
+ * blocks. A transaction can contain multiple inputs and outputs.
+ */
+class CTransaction
+{
+private:
+ /** Memory only. */
+ const uint256 hash;
+ void UpdateHash() const;
+
+public:
+ static const int32_t CURRENT_VERSION=1;
+
+ // The local variables are made const to prevent unintended modification
+ // without updating the cached hash value. However, CTransaction is not
+ // actually immutable; deserialization and assignment are implemented,
+ // and bypass the constness. This is safe, as they update the entire
+ // structure, including the hash.
+ const int32_t nVersion;
+ const std::vector<CTxIn> vin;
+ const std::vector<CTxOut> vout;
+ const uint32_t nLockTime;
+
+ /** Construct a CTransaction that qualifies as IsNull() */
+ CTransaction();
+
+ /** Convert a CMutableTransaction into a CTransaction. */
+ CTransaction(const CMutableTransaction &tx);
+
+ CTransaction& operator=(const CTransaction& tx);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(*const_cast<int32_t*>(&this->nVersion));
+ nVersion = this->nVersion;
+ READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
+ READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
+ READWRITE(*const_cast<uint32_t*>(&nLockTime));
+ if (ser_action.ForRead())
+ UpdateHash();
+ }
+
+ bool IsNull() const {
+ return vin.empty() && vout.empty();
+ }
+
+ const uint256& GetHash() const {
+ return hash;
+ }
+
+ // Return sum of txouts.
+ CAmount GetValueOut() const;
+ // GetValueIn() is a method on CCoinsViewCache, because
+ // inputs must be known to compute value in.
+
+ // Compute priority, given priority of inputs and (optionally) tx size
+ double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
+
+ // Compute modified tx size for priority calculation (optionally given tx size)
+ unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
+
+ bool IsCoinBase() const
+ {
+ return (vin.size() == 1 && vin[0].prevout.IsNull());
+ }
+
+ friend bool operator==(const CTransaction& a, const CTransaction& b)
+ {
+ return a.hash == b.hash;
+ }
+
+ friend bool operator!=(const CTransaction& a, const CTransaction& b)
+ {
+ return a.hash != b.hash;
+ }
+
+ std::string ToString() const;
+};
+
+/** A mutable version of CTransaction. */
+struct CMutableTransaction
+{
+ int32_t nVersion;
+ std::vector<CTxIn> vin;
+ std::vector<CTxOut> vout;
+ uint32_t nLockTime;
+
+ CMutableTransaction();
+ CMutableTransaction(const CTransaction& tx);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(vin);
+ READWRITE(vout);
+ READWRITE(nLockTime);
+ }
+
+ /** Compute the hash of this CMutableTransaction. This is computed on the
+ * fly, as opposed to GetHash() in CTransaction, which uses a cached result.
+ */
+ uint256 GetHash() const;
+};
+
+#endif // H_BITCOIN_CORE_TRANSACTION
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 8b85a03c54..d39bc9a780 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -4,9 +4,10 @@
#include "core_io.h"
-#include "core.h"
+#include "core/transaction.h"
#include "script/script.h"
#include "serialize.h"
+#include "streams.h"
#include "univalue/univalue.h"
#include "util.h"
#include "utilstrencodings.h"
diff --git a/src/core_write.cpp b/src/core_write.cpp
index e42e0b62a9..a3ae8eec07 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -5,10 +5,11 @@
#include "core_io.h"
#include "base58.h"
-#include "core.h"
+#include "core/transaction.h"
#include "script/script.h"
#include "script/standard.h"
#include "serialize.h"
+#include "streams.h"
#include "univalue/univalue.h"
#include "util.h"
#include "utilmoneystr.h"
diff --git a/src/db.h b/src/db.h
index d202399383..0cbdd8b91b 100644
--- a/src/db.h
+++ b/src/db.h
@@ -7,6 +7,7 @@
#define BITCOIN_DB_H
#include "serialize.h"
+#include "streams.h"
#include "sync.h"
#include "version.h"
diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp
new file mode 100644
index 0000000000..e5db670927
--- /dev/null
+++ b/src/ecwrapper.cpp
@@ -0,0 +1,333 @@
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "ecwrapper.h"
+
+#include "serialize.h"
+#include "uint256.h"
+
+#include <openssl/bn.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+
+namespace {
+
+// Generate a private key from just the secret parameter
+int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
+{
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+ EC_POINT *pub_key = NULL;
+
+ if (!eckey) return 0;
+
+ const EC_GROUP *group = EC_KEY_get0_group(eckey);
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ goto err;
+
+ pub_key = EC_POINT_new(group);
+
+ if (pub_key == NULL)
+ goto err;
+
+ if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
+ goto err;
+
+ EC_KEY_set_private_key(eckey,priv_key);
+ EC_KEY_set_public_key(eckey,pub_key);
+
+ ok = 1;
+
+err:
+
+ if (pub_key)
+ EC_POINT_free(pub_key);
+ if (ctx != NULL)
+ BN_CTX_free(ctx);
+
+ return(ok);
+}
+
+// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
+// recid selects which key is recovered
+// if check is non-zero, additional checks are performed
+int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
+{
+ if (!eckey) return 0;
+
+ int ret = 0;
+ BN_CTX *ctx = NULL;
+
+ BIGNUM *x = NULL;
+ BIGNUM *e = NULL;
+ BIGNUM *order = NULL;
+ BIGNUM *sor = NULL;
+ BIGNUM *eor = NULL;
+ BIGNUM *field = NULL;
+ EC_POINT *R = NULL;
+ EC_POINT *O = NULL;
+ EC_POINT *Q = NULL;
+ BIGNUM *rr = NULL;
+ BIGNUM *zero = NULL;
+ int n = 0;
+ int i = recid / 2;
+
+ const EC_GROUP *group = EC_KEY_get0_group(eckey);
+ if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
+ BN_CTX_start(ctx);
+ order = BN_CTX_get(ctx);
+ if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
+ x = BN_CTX_get(ctx);
+ if (!BN_copy(x, order)) { ret=-1; goto err; }
+ if (!BN_mul_word(x, i)) { ret=-1; goto err; }
+ if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
+ field = BN_CTX_get(ctx);
+ if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
+ if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
+ if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
+ if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
+ if (check)
+ {
+ if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
+ if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
+ if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
+ }
+ if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
+ n = EC_GROUP_get_degree(group);
+ e = BN_CTX_get(ctx);
+ if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
+ if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
+ zero = BN_CTX_get(ctx);
+ if (!BN_zero(zero)) { ret=-1; goto err; }
+ if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
+ rr = BN_CTX_get(ctx);
+ if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
+ sor = BN_CTX_get(ctx);
+ if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
+ eor = BN_CTX_get(ctx);
+ if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
+ if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
+ if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
+
+ ret = 1;
+
+err:
+ if (ctx) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ if (R != NULL) EC_POINT_free(R);
+ if (O != NULL) EC_POINT_free(O);
+ if (Q != NULL) EC_POINT_free(Q);
+ return ret;
+}
+
+} // anon namespace
+
+CECKey::CECKey() {
+ pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ assert(pkey != NULL);
+}
+
+CECKey::~CECKey() {
+ EC_KEY_free(pkey);
+}
+
+void CECKey::GetSecretBytes(unsigned char vch[32]) const {
+ const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
+ assert(bn);
+ int nBytes = BN_num_bytes(bn);
+ int n=BN_bn2bin(bn,&vch[32 - nBytes]);
+ assert(n == nBytes);
+ memset(vch, 0, 32 - nBytes);
+}
+
+void CECKey::SetSecretBytes(const unsigned char vch[32]) {
+ bool ret;
+ BIGNUM bn;
+ BN_init(&bn);
+ ret = BN_bin2bn(vch, 32, &bn) != NULL;
+ assert(ret);
+ ret = EC_KEY_regenerate_key(pkey, &bn) != 0;
+ assert(ret);
+ BN_clear_free(&bn);
+}
+
+int CECKey::GetPrivKeySize(bool fCompressed) {
+ EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
+ return i2d_ECPrivateKey(pkey, NULL);
+}
+int CECKey::GetPrivKey(unsigned char* privkey, bool fCompressed) {
+ EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
+ return i2d_ECPrivateKey(pkey, &privkey);
+}
+
+bool CECKey::SetPrivKey(const unsigned char* privkey, size_t size, bool fSkipCheck) {
+ if (d2i_ECPrivateKey(&pkey, &privkey, size)) {
+ if(fSkipCheck)
+ return true;
+
+ // d2i_ECPrivateKey returns true if parsing succeeds.
+ // This doesn't necessarily mean the key is valid.
+ if (EC_KEY_check_key(pkey))
+ return true;
+ }
+ return false;
+}
+
+void CECKey::GetPubKey(std::vector<unsigned char> &pubkey, bool fCompressed) {
+ EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
+ int nSize = i2o_ECPublicKey(pkey, NULL);
+ assert(nSize);
+ assert(nSize <= 65);
+ pubkey.clear();
+ pubkey.resize(nSize);
+ unsigned char *pbegin(begin_ptr(pubkey));
+ int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
+ assert(nSize == nSize2);
+}
+
+bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) {
+ return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL;
+}
+
+bool CECKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) {
+ vchSig.clear();
+ ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
+ if (sig == NULL)
+ return false;
+ BN_CTX *ctx = BN_CTX_new();
+ BN_CTX_start(ctx);
+ const EC_GROUP *group = EC_KEY_get0_group(pkey);
+ BIGNUM *order = BN_CTX_get(ctx);
+ BIGNUM *halforder = BN_CTX_get(ctx);
+ EC_GROUP_get_order(group, order, ctx);
+ BN_rshift1(halforder, order);
+ if (lowS && BN_cmp(sig->s, halforder) > 0) {
+ // enforce low S values, by negating the value (modulo the order) if above order/2.
+ BN_sub(sig->s, order, sig->s);
+ }
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ unsigned int nSize = ECDSA_size(pkey);
+ vchSig.resize(nSize); // Make sure it is big enough
+ unsigned char *pos = &vchSig[0];
+ nSize = i2d_ECDSA_SIG(sig, &pos);
+ ECDSA_SIG_free(sig);
+ vchSig.resize(nSize); // Shrink to fit actual size
+ return true;
+}
+
+bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
+ // -1 = error, 0 = bad sig, 1 = good
+ if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+ return false;
+ return true;
+}
+
+bool CECKey::SignCompact(const uint256 &hash, unsigned char *p64, int &rec) {
+ bool fOk = false;
+ ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
+ if (sig==NULL)
+ return false;
+ memset(p64, 0, 64);
+ int nBitsR = BN_num_bits(sig->r);
+ int nBitsS = BN_num_bits(sig->s);
+ if (nBitsR <= 256 && nBitsS <= 256) {
+ std::vector<unsigned char> pubkey;
+ GetPubKey(pubkey, true);
+ for (int i=0; i<4; i++) {
+ CECKey keyRec;
+ if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
+ std::vector<unsigned char> pubkeyRec;
+ keyRec.GetPubKey(pubkeyRec, true);
+ if (pubkeyRec == pubkey) {
+ rec = i;
+ fOk = true;
+ break;
+ }
+ }
+ }
+ assert(fOk);
+ BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
+ BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
+ }
+ ECDSA_SIG_free(sig);
+ return fOk;
+}
+
+bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
+{
+ if (rec<0 || rec>=3)
+ return false;
+ ECDSA_SIG *sig = ECDSA_SIG_new();
+ BN_bin2bn(&p64[0], 32, sig->r);
+ BN_bin2bn(&p64[32], 32, sig->s);
+ bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
+ ECDSA_SIG_free(sig);
+ return ret;
+}
+
+bool CECKey::TweakSecret(unsigned char vchSecretOut[32], const unsigned char vchSecretIn[32], const unsigned char vchTweak[32])
+{
+ bool ret = true;
+ BN_CTX *ctx = BN_CTX_new();
+ BN_CTX_start(ctx);
+ BIGNUM *bnSecret = BN_CTX_get(ctx);
+ BIGNUM *bnTweak = BN_CTX_get(ctx);
+ BIGNUM *bnOrder = BN_CTX_get(ctx);
+ EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1);
+ EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order...
+ BN_bin2bn(vchTweak, 32, bnTweak);
+ if (BN_cmp(bnTweak, bnOrder) >= 0)
+ ret = false; // extremely unlikely
+ BN_bin2bn(vchSecretIn, 32, bnSecret);
+ BN_add(bnSecret, bnSecret, bnTweak);
+ BN_nnmod(bnSecret, bnSecret, bnOrder, ctx);
+ if (BN_is_zero(bnSecret))
+ ret = false; // ridiculously unlikely
+ int nBits = BN_num_bits(bnSecret);
+ memset(vchSecretOut, 0, 32);
+ BN_bn2bin(bnSecret, &vchSecretOut[32-(nBits+7)/8]);
+ EC_GROUP_free(group);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+bool CECKey::TweakPublic(const unsigned char vchTweak[32]) {
+ bool ret = true;
+ BN_CTX *ctx = BN_CTX_new();
+ BN_CTX_start(ctx);
+ BIGNUM *bnTweak = BN_CTX_get(ctx);
+ BIGNUM *bnOrder = BN_CTX_get(ctx);
+ BIGNUM *bnOne = BN_CTX_get(ctx);
+ const EC_GROUP *group = EC_KEY_get0_group(pkey);
+ EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order...
+ BN_bin2bn(vchTweak, 32, bnTweak);
+ if (BN_cmp(bnTweak, bnOrder) >= 0)
+ ret = false; // extremely unlikely
+ EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group);
+ BN_one(bnOne);
+ EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx);
+ if (EC_POINT_is_at_infinity(group, point))
+ ret = false; // ridiculously unlikely
+ EC_KEY_set_public_key(pkey, point);
+ EC_POINT_free(point);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+bool CECKey::SanityCheck()
+{
+ EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if(pkey == NULL)
+ return false;
+ EC_KEY_free(pkey);
+
+ // TODO Is there more EC functionality that could be missing?
+ return true;
+}
diff --git a/src/ecwrapper.h b/src/ecwrapper.h
new file mode 100644
index 0000000000..072da4a942
--- /dev/null
+++ b/src/ecwrapper.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_EC_WRAPPER_H
+#define BITCOIN_EC_WRAPPER_H
+
+#include <cstddef>
+#include <vector>
+
+#include <openssl/ec.h>
+
+class uint256;
+
+// RAII Wrapper around OpenSSL's EC_KEY
+class CECKey {
+private:
+ EC_KEY *pkey;
+
+public:
+ CECKey();
+ ~CECKey();
+
+ void GetSecretBytes(unsigned char vch[32]) const;
+ void SetSecretBytes(const unsigned char vch[32]);
+ int GetPrivKeySize(bool fCompressed);
+ int GetPrivKey(unsigned char* privkey, bool fCompressed);
+ bool SetPrivKey(const unsigned char* privkey, size_t size, bool fSkipCheck=false);
+ void GetPubKey(std::vector<unsigned char>& pubkey, bool fCompressed);
+ bool SetPubKey(const unsigned char* pubkey, size_t size);
+ bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS);
+ bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig);
+ bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec);
+
+ // reconstruct public key from a compact signature
+ // This is only slightly more CPU intensive than just verifying it.
+ // If this function succeeds, the recovered public key is guaranteed to be valid
+ // (the signature is a valid signature of the given data for that key)
+ bool Recover(const uint256 &hash, const unsigned char *p64, int rec);
+
+ static bool TweakSecret(unsigned char vchSecretOut[32], const unsigned char vchSecretIn[32], const unsigned char vchTweak[32]);
+ bool TweakPublic(const unsigned char vchTweak[32]);
+ static bool SanityCheck();
+};
+
+#endif
diff --git a/src/init.cpp b/src/init.cpp
index 70ac5190d3..d928094bba 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -10,6 +10,7 @@
#include "init.h"
#include "addrman.h"
+#include "amount.h"
#include "checkpoints.h"
#include "compat/sanity.h"
#include "key.h"
diff --git a/src/key.cpp b/src/key.cpp
index 079e2c6540..c466e84f26 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "key.h"
@@ -10,12 +10,10 @@
#ifdef USE_SECP256K1
#include <secp256k1.h>
#else
-#include <openssl/bn.h>
-#include <openssl/ecdsa.h>
-#include <openssl/obj_mac.h>
+#include "ecwrapper.h"
#endif
-// anonymous namespace with local implementation code (OpenSSL interaction)
+//! anonymous namespace
namespace {
#ifdef USE_SECP256K1
@@ -31,326 +29,6 @@ public:
};
static CSecp256k1Init instance_of_csecp256k1;
-#else
-
-// Generate a private key from just the secret parameter
-int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
-{
- int ok = 0;
- BN_CTX *ctx = NULL;
- EC_POINT *pub_key = NULL;
-
- if (!eckey) return 0;
-
- const EC_GROUP *group = EC_KEY_get0_group(eckey);
-
- if ((ctx = BN_CTX_new()) == NULL)
- goto err;
-
- pub_key = EC_POINT_new(group);
-
- if (pub_key == NULL)
- goto err;
-
- if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
- goto err;
-
- EC_KEY_set_private_key(eckey,priv_key);
- EC_KEY_set_public_key(eckey,pub_key);
-
- ok = 1;
-
-err:
-
- if (pub_key)
- EC_POINT_free(pub_key);
- if (ctx != NULL)
- BN_CTX_free(ctx);
-
- return(ok);
-}
-
-// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
-// recid selects which key is recovered
-// if check is non-zero, additional checks are performed
-int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
-{
- if (!eckey) return 0;
-
- int ret = 0;
- BN_CTX *ctx = NULL;
-
- BIGNUM *x = NULL;
- BIGNUM *e = NULL;
- BIGNUM *order = NULL;
- BIGNUM *sor = NULL;
- BIGNUM *eor = NULL;
- BIGNUM *field = NULL;
- EC_POINT *R = NULL;
- EC_POINT *O = NULL;
- EC_POINT *Q = NULL;
- BIGNUM *rr = NULL;
- BIGNUM *zero = NULL;
- int n = 0;
- int i = recid / 2;
-
- const EC_GROUP *group = EC_KEY_get0_group(eckey);
- if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
- BN_CTX_start(ctx);
- order = BN_CTX_get(ctx);
- if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
- x = BN_CTX_get(ctx);
- if (!BN_copy(x, order)) { ret=-1; goto err; }
- if (!BN_mul_word(x, i)) { ret=-1; goto err; }
- if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
- field = BN_CTX_get(ctx);
- if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
- if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
- if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
- if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
- if (check)
- {
- if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
- if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
- if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
- }
- if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
- n = EC_GROUP_get_degree(group);
- e = BN_CTX_get(ctx);
- if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
- if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
- zero = BN_CTX_get(ctx);
- if (!BN_zero(zero)) { ret=-1; goto err; }
- if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
- rr = BN_CTX_get(ctx);
- if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
- sor = BN_CTX_get(ctx);
- if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
- eor = BN_CTX_get(ctx);
- if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
- if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
- if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
-
- ret = 1;
-
-err:
- if (ctx) {
- BN_CTX_end(ctx);
- BN_CTX_free(ctx);
- }
- if (R != NULL) EC_POINT_free(R);
- if (O != NULL) EC_POINT_free(O);
- if (Q != NULL) EC_POINT_free(Q);
- return ret;
-}
-
-// RAII Wrapper around OpenSSL's EC_KEY
-class CECKey {
-private:
- EC_KEY *pkey;
-
-public:
- CECKey() {
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- assert(pkey != NULL);
- }
-
- ~CECKey() {
- EC_KEY_free(pkey);
- }
-
- void GetSecretBytes(unsigned char vch[32]) const {
- const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
- assert(bn);
- int nBytes = BN_num_bytes(bn);
- int n=BN_bn2bin(bn,&vch[32 - nBytes]);
- assert(n == nBytes);
- memset(vch, 0, 32 - nBytes);
- }
-
- void SetSecretBytes(const unsigned char vch[32]) {
- bool ret;
- BIGNUM bn;
- BN_init(&bn);
- ret = BN_bin2bn(vch, 32, &bn) != NULL;
- assert(ret);
- ret = EC_KEY_regenerate_key(pkey, &bn) != 0;
- assert(ret);
- BN_clear_free(&bn);
- }
-
- int GetPrivKeySize(bool fCompressed) {
- EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
- return i2d_ECPrivateKey(pkey, NULL);
- }
- int GetPrivKey(unsigned char* privkey, bool fCompressed) {
- EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
- return i2d_ECPrivateKey(pkey, &privkey);
- }
-
- bool SetPrivKey(const unsigned char* privkey, size_t size, bool fSkipCheck=false) {
- if (d2i_ECPrivateKey(&pkey, &privkey, size)) {
- if(fSkipCheck)
- return true;
-
- // d2i_ECPrivateKey returns true if parsing succeeds.
- // This doesn't necessarily mean the key is valid.
- if (EC_KEY_check_key(pkey))
- return true;
- }
- return false;
- }
-
- void GetPubKey(CPubKey &pubkey, bool fCompressed) {
- EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
- int nSize = i2o_ECPublicKey(pkey, NULL);
- assert(nSize);
- assert(nSize <= 65);
- unsigned char c[65];
- unsigned char *pbegin = c;
- int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
- assert(nSize == nSize2);
- pubkey.Set(&c[0], &c[nSize]);
- }
-
- bool SetPubKey(const CPubKey &pubkey) {
- const unsigned char* pbegin = pubkey.begin();
- return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size()) != NULL;
- }
-
- bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) {
- vchSig.clear();
- ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
- if (sig == NULL)
- return false;
- BN_CTX *ctx = BN_CTX_new();
- BN_CTX_start(ctx);
- const EC_GROUP *group = EC_KEY_get0_group(pkey);
- BIGNUM *order = BN_CTX_get(ctx);
- BIGNUM *halforder = BN_CTX_get(ctx);
- EC_GROUP_get_order(group, order, ctx);
- BN_rshift1(halforder, order);
- if (lowS && BN_cmp(sig->s, halforder) > 0) {
- // enforce low S values, by negating the value (modulo the order) if above order/2.
- BN_sub(sig->s, order, sig->s);
- }
- BN_CTX_end(ctx);
- BN_CTX_free(ctx);
- unsigned int nSize = ECDSA_size(pkey);
- vchSig.resize(nSize); // Make sure it is big enough
- unsigned char *pos = &vchSig[0];
- nSize = i2d_ECDSA_SIG(sig, &pos);
- ECDSA_SIG_free(sig);
- vchSig.resize(nSize); // Shrink to fit actual size
- return true;
- }
-
- bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
- // -1 = error, 0 = bad sig, 1 = good
- if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
- return false;
- return true;
- }
-
- bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec) {
- bool fOk = false;
- ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
- if (sig==NULL)
- return false;
- memset(p64, 0, 64);
- int nBitsR = BN_num_bits(sig->r);
- int nBitsS = BN_num_bits(sig->s);
- if (nBitsR <= 256 && nBitsS <= 256) {
- CPubKey pubkey;
- GetPubKey(pubkey, true);
- for (int i=0; i<4; i++) {
- CECKey keyRec;
- if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
- CPubKey pubkeyRec;
- keyRec.GetPubKey(pubkeyRec, true);
- if (pubkeyRec == pubkey) {
- rec = i;
- fOk = true;
- break;
- }
- }
- }
- assert(fOk);
- BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
- BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
- }
- ECDSA_SIG_free(sig);
- return fOk;
- }
-
- // reconstruct public key from a compact signature
- // This is only slightly more CPU intensive than just verifying it.
- // If this function succeeds, the recovered public key is guaranteed to be valid
- // (the signature is a valid signature of the given data for that key)
- bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
- {
- if (rec<0 || rec>=3)
- return false;
- ECDSA_SIG *sig = ECDSA_SIG_new();
- BN_bin2bn(&p64[0], 32, sig->r);
- BN_bin2bn(&p64[32], 32, sig->s);
- bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
- ECDSA_SIG_free(sig);
- return ret;
- }
-
- static bool TweakSecret(unsigned char vchSecretOut[32], const unsigned char vchSecretIn[32], const unsigned char vchTweak[32])
- {
- bool ret = true;
- BN_CTX *ctx = BN_CTX_new();
- BN_CTX_start(ctx);
- BIGNUM *bnSecret = BN_CTX_get(ctx);
- BIGNUM *bnTweak = BN_CTX_get(ctx);
- BIGNUM *bnOrder = BN_CTX_get(ctx);
- EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1);
- EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order...
- BN_bin2bn(vchTweak, 32, bnTweak);
- if (BN_cmp(bnTweak, bnOrder) >= 0)
- ret = false; // extremely unlikely
- BN_bin2bn(vchSecretIn, 32, bnSecret);
- BN_add(bnSecret, bnSecret, bnTweak);
- BN_nnmod(bnSecret, bnSecret, bnOrder, ctx);
- if (BN_is_zero(bnSecret))
- ret = false; // ridiculously unlikely
- int nBits = BN_num_bits(bnSecret);
- memset(vchSecretOut, 0, 32);
- BN_bn2bin(bnSecret, &vchSecretOut[32-(nBits+7)/8]);
- EC_GROUP_free(group);
- BN_CTX_end(ctx);
- BN_CTX_free(ctx);
- return ret;
- }
-
- bool TweakPublic(const unsigned char vchTweak[32]) {
- bool ret = true;
- BN_CTX *ctx = BN_CTX_new();
- BN_CTX_start(ctx);
- BIGNUM *bnTweak = BN_CTX_get(ctx);
- BIGNUM *bnOrder = BN_CTX_get(ctx);
- BIGNUM *bnOne = BN_CTX_get(ctx);
- const EC_GROUP *group = EC_KEY_get0_group(pkey);
- EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order...
- BN_bin2bn(vchTweak, 32, bnTweak);
- if (BN_cmp(bnTweak, bnOrder) >= 0)
- ret = false; // extremely unlikely
- EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group);
- BN_one(bnOne);
- EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx);
- if (EC_POINT_is_at_infinity(group, point))
- ret = false; // ridiculously unlikely
- EC_KEY_set_public_key(pkey, point);
- EC_POINT_free(point);
- BN_CTX_end(ctx);
- BN_CTX_free(ctx);
- return ret;
- }
-};
-
#endif
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
@@ -378,7 +56,7 @@ int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char
return 0;
}
-// Order of secp256k1's generator minus 1.
+/** Order of secp256k1's generator minus 1. */
const unsigned char vchMaxModOrder[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
@@ -386,7 +64,7 @@ const unsigned char vchMaxModOrder[32] = {
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
-// Half of the order of secp256k1's generator minus 1.
+/** Half of the order of secp256k1's generator minus 1. */
const unsigned char vchMaxModHalfOrder[32] = {
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
@@ -455,19 +133,21 @@ CPrivKey CKey::GetPrivKey() const {
CPubKey CKey::GetPubKey() const {
assert(fValid);
- CPubKey pubkey;
+ CPubKey result;
#ifdef USE_SECP256K1
int clen = 65;
- int ret = secp256k1_ecdsa_pubkey_create((unsigned char*)pubkey.begin(), &clen, begin(), fCompressed);
+ int ret = secp256k1_ecdsa_pubkey_create((unsigned char*)result.begin(), &clen, begin(), fCompressed);
+ assert((int)result.size() == clen);
assert(ret);
- assert(pubkey.IsValid());
- assert((int)pubkey.size() == clen);
#else
+ std::vector<unsigned char> pubkey;
CECKey key;
key.SetSecretBytes(vch);
key.GetPubKey(pubkey, fCompressed);
+ result.Set(pubkey.begin(), pubkey.end());
#endif
- return pubkey;
+ assert(result.IsValid());
+ return result;
}
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) const {
@@ -544,7 +224,7 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
return false;
#else
CECKey key;
- if (!key.SetPubKey(*this))
+ if (!key.SetPubKey(begin(), size()))
return false;
if (!key.Verify(hash, vchSig))
return false;
@@ -566,7 +246,9 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha
CECKey key;
if (!key.Recover(hash, &vchSig[1], recid))
return false;
- key.GetPubKey(*this, fComp);
+ std::vector<unsigned char> pubkey;
+ key.GetPubKey(pubkey, fComp);
+ Set(pubkey.begin(), pubkey.end());
#endif
return true;
}
@@ -579,7 +261,7 @@ bool CPubKey::IsFullyValid() const {
return false;
#else
CECKey key;
- if (!key.SetPubKey(*this))
+ if (!key.SetPubKey(begin(), size()))
return false;
#endif
return true;
@@ -595,9 +277,11 @@ bool CPubKey::Decompress() {
assert(clen == (int)size());
#else
CECKey key;
- if (!key.SetPubKey(*this))
+ if (!key.SetPubKey(begin(), size()))
return false;
- key.GetPubKey(*this, false);
+ std::vector<unsigned char> pubkey;
+ key.GetPubKey(pubkey, false);
+ Set(pubkey.begin(), pubkey.end());
#endif
return true;
}
@@ -652,9 +336,11 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned i
bool ret = secp256k1_ecdsa_pubkey_tweak_add((unsigned char*)pubkeyChild.begin(), pubkeyChild.size(), out);
#else
CECKey key;
- bool ret = key.SetPubKey(*this);
+ bool ret = key.SetPubKey(begin(), size());
ret &= key.TweakPublic(out);
- key.GetPubKey(pubkeyChild, true);
+ std::vector<unsigned char> pubkey;
+ key.GetPubKey(pubkey, true);
+ pubkeyChild.Set(pubkey.begin(), pubkey.end());
#endif
return ret;
}
@@ -739,12 +425,6 @@ bool ECC_InitSanityCheck() {
#ifdef USE_SECP256K1
return true;
#else
- EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if(pkey == NULL)
- return false;
- EC_KEY_free(pkey);
-
- // TODO Is there more EC functionality that could be missing?
- return true;
+ return CECKey::SanityCheck();
#endif
}
diff --git a/src/key.h b/src/key.h
index 48b1652536..b4cb647681 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEY_H
@@ -14,13 +14,15 @@
#include <stdexcept>
#include <vector>
-// secp256k1:
-// const unsigned int PRIVATE_KEY_SIZE = 279;
-// const unsigned int PUBLIC_KEY_SIZE = 65;
-// const unsigned int SIGNATURE_SIZE = 72;
-//
-// see www.keylength.com
-// script supports up to 75 for single byte push
+/**
+ * secp256k1:
+ * const unsigned int PRIVATE_KEY_SIZE = 279;
+ * const unsigned int PUBLIC_KEY_SIZE = 65;
+ * const unsigned int SIGNATURE_SIZE = 72;
+ *
+ * see www.keylength.com
+ * script supports up to 75 for single byte push
+ */
/** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160
@@ -34,11 +36,14 @@ public:
class CPubKey
{
private:
- // Just store the serialized data.
- // Its length can very cheaply be computed from the first byte.
+
+ /**
+ * Just store the serialized data.
+ * Its length can very cheaply be computed from the first byte.
+ */
unsigned char vch[65];
- // Compute the length of a pubkey with a given first byte.
+ //! Compute the length of a pubkey with a given first byte.
unsigned int static GetLen(unsigned char chHeader)
{
if (chHeader == 2 || chHeader == 3)
@@ -48,20 +53,20 @@ private:
return 0;
}
- // Set this key data to be invalid
+ //! Set this key data to be invalid
void Invalidate()
{
vch[0] = 0xFF;
}
public:
- // Construct an invalid public key.
+ //! Construct an invalid public key.
CPubKey()
{
Invalidate();
}
- // Initialize a public key using begin/end iterators to byte data.
+ //! Initialize a public key using begin/end iterators to byte data.
template <typename T>
void Set(const T pbegin, const T pend)
{
@@ -72,26 +77,26 @@ public:
Invalidate();
}
- // Construct a public key using begin/end iterators to byte data.
+ //! Construct a public key using begin/end iterators to byte data.
template <typename T>
CPubKey(const T pbegin, const T pend)
{
Set(pbegin, pend);
}
- // Construct a public key from a byte vector.
+ //! Construct a public key from a byte vector.
CPubKey(const std::vector<unsigned char>& vch)
{
Set(vch.begin(), vch.end());
}
- // Simple read-only vector-like interface to the pubkey data.
+ //! Simple read-only vector-like interface to the pubkey data.
unsigned int size() const { return GetLen(vch[0]); }
const unsigned char* begin() const { return vch; }
const unsigned char* end() const { return vch + size(); }
const unsigned char& operator[](unsigned int pos) const { return vch[pos]; }
- // Comparator implementation.
+ //! Comparator implementation.
friend bool operator==(const CPubKey& a, const CPubKey& b)
{
return a.vch[0] == b.vch[0] &&
@@ -107,7 +112,7 @@ public:
(a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
}
- // Implement serialization, as if this was a byte vector.
+ //! Implement serialization, as if this was a byte vector.
unsigned int GetSerializeSize(int nType, int nVersion) const
{
return size() + 1;
@@ -134,86 +139,92 @@ public:
}
}
- // Get the KeyID of this public key (hash of its serialization)
+ //! Get the KeyID of this public key (hash of its serialization)
CKeyID GetID() const
{
return CKeyID(Hash160(vch, vch + size()));
}
- // Get the 256-bit hash of this public key.
+ //! Get the 256-bit hash of this public key.
uint256 GetHash() const
{
return Hash(vch, vch + size());
}
- // Check syntactic correctness.
- //
- // Note that this is consensus critical as CheckSig() calls it!
+ /*
+ * Check syntactic correctness.
+ *
+ * Note that this is consensus critical as CheckSig() calls it!
+ */
bool IsValid() const
{
return size() > 0;
}
- // fully validate whether this is a valid public key (more expensive than IsValid())
+ //! fully validate whether this is a valid public key (more expensive than IsValid())
bool IsFullyValid() const;
- // Check whether this is a compressed public key.
+ //! Check whether this is a compressed public key.
bool IsCompressed() const
{
return size() == 33;
}
- // Verify a DER signature (~72 bytes).
- // If this public key is not fully valid, the return value will be false.
+ /**
+ * Verify a DER signature (~72 bytes).
+ * If this public key is not fully valid, the return value will be false.
+ */
bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
- // Recover a public key from a compact signature.
+ //! Recover a public key from a compact signature.
bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
- // Turn this public key into an uncompressed public key.
+ //! Turn this public key into an uncompressed public key.
bool Decompress();
- // Derive BIP32 child pubkey.
+ //! Derive BIP32 child pubkey.
bool Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const;
};
-// secure_allocator is defined in allocators.h
-// CPrivKey is a serialized private key, with all parameters included (279 bytes)
+/**
+ * secure_allocator is defined in allocators.h
+ * CPrivKey is a serialized private key, with all parameters included (279 bytes)
+ */
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
/** An encapsulated private key. */
class CKey
{
private:
- // Whether this private key is valid. We check for correctness when modifying the key
- // data, so fValid should always correspond to the actual state.
+ //! Whether this private key is valid. We check for correctness when modifying the key
+ //! data, so fValid should always correspond to the actual state.
bool fValid;
- // Whether the public key corresponding to this private key is (to be) compressed.
+ //! Whether the public key corresponding to this private key is (to be) compressed.
bool fCompressed;
- // The actual byte data
+ //! The actual byte data
unsigned char vch[32];
- // Check whether the 32-byte array pointed to be vch is valid keydata.
+ //! Check whether the 32-byte array pointed to be vch is valid keydata.
bool static Check(const unsigned char* vch);
public:
- // Construct an invalid private key.
+ //! Construct an invalid private key.
CKey() : fValid(false), fCompressed(false)
{
LockObject(vch);
}
- // Copy constructor. This is necessary because of memlocking.
+ //! Copy constructor. This is necessary because of memlocking.
CKey(const CKey& secret) : fValid(secret.fValid), fCompressed(secret.fCompressed)
{
LockObject(vch);
memcpy(vch, secret.vch, sizeof(vch));
}
- // Destructor (again necessary because of memlocking).
+ //! Destructor (again necessary because of memlocking).
~CKey()
{
UnlockObject(vch);
@@ -225,7 +236,7 @@ public:
memcmp(&a.vch[0], &b.vch[0], a.size()) == 0;
}
- // Initialize using begin and end iterators to byte data.
+ //! Initialize using begin and end iterators to byte data.
template <typename T>
void Set(const T pbegin, const T pend, bool fCompressedIn)
{
@@ -242,48 +253,54 @@ public:
}
}
- // Simple read-only vector-like interface.
+ //! Simple read-only vector-like interface.
unsigned int size() const { return (fValid ? 32 : 0); }
const unsigned char* begin() const { return vch; }
const unsigned char* end() const { return vch + size(); }
- // Check whether this private key is valid.
+ //! Check whether this private key is valid.
bool IsValid() const { return fValid; }
- // Check whether the public key corresponding to this private key is (to be) compressed.
+ //! Check whether the public key corresponding to this private key is (to be) compressed.
bool IsCompressed() const { return fCompressed; }
- // Initialize from a CPrivKey (serialized OpenSSL private key data).
+ //! Initialize from a CPrivKey (serialized OpenSSL private key data).
bool SetPrivKey(const CPrivKey& vchPrivKey, bool fCompressed);
- // Generate a new private key using a cryptographic PRNG.
+ //! Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed);
- // Convert the private key to a CPrivKey (serialized OpenSSL private key data).
- // This is expensive.
+ /**
+ * Convert the private key to a CPrivKey (serialized OpenSSL private key data).
+ * This is expensive.
+ */
CPrivKey GetPrivKey() const;
- // Compute the public key from a private key.
- // This is expensive.
+ /**
+ * Compute the public key from a private key.
+ * This is expensive.
+ */
CPubKey GetPubKey() const;
- // Create a DER-serialized signature.
+ //! Create a DER-serialized signature.
bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, bool lowS = true) const;
- // Create a compact signature (65 bytes), which allows reconstructing the used public key.
- // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
- // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
- // 0x1D = second key with even y, 0x1E = second key with odd y,
- // add 0x04 for compressed keys.
+ /**
+ * Create a compact signature (65 bytes), which allows reconstructing the used public key.
+ * The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
+ * The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
+ * 0x1D = second key with even y, 0x1E = second key with odd y,
+ * add 0x04 for compressed keys.
+ */
bool SignCompact(const uint256& hash, std::vector<unsigned char>& vchSig) const;
- // Derive BIP32 child key.
+ //! Derive BIP32 child key.
bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const;
- // Load private key and check that public key matches.
+ //! Load private key and check that public key matches.
bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck);
- // Check whether an element of a signature (r or s) is valid.
+ //! Check whether an element of a signature (r or s) is valid.
static bool CheckSignatureElement(const unsigned char* vch, int len, bool half);
};
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 039c690625..879f099720 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "keystore.h"
diff --git a/src/keystore.h b/src/keystore.h
index 4f8189c8f5..66f8771d4a 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYSTORE_H
@@ -24,22 +24,22 @@ protected:
public:
virtual ~CKeyStore() {}
- // Add a key to the store.
+ //! Add a key to the store.
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
virtual bool AddKey(const CKey &key);
- // Check whether a key corresponding to a given address is present in the store.
+ //! Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0;
virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;
virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;
virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
- // Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
+ //! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
- // Support for Watch-only addresses
+ //! Support for Watch-only addresses
virtual bool AddWatchOnly(const CScript &dest) =0;
virtual bool RemoveWatchOnly(const CScript &dest) =0;
virtual bool HaveWatchOnly(const CScript &dest) const =0;
diff --git a/src/leveldb/CONTRIBUTING.md b/src/leveldb/CONTRIBUTING.md
new file mode 100644
index 0000000000..cd600ff46b
--- /dev/null
+++ b/src/leveldb/CONTRIBUTING.md
@@ -0,0 +1,36 @@
+# Contributing
+
+We'd love to accept your code patches! However, before we can take them, we
+have to jump a couple of legal hurdles.
+
+## Contributor License Agreements
+
+Please fill out either the individual or corporate Contributor License
+Agreement as appropriate.
+
+* If you are an individual writing original source code and you're sure you
+own the intellectual property, then sign an [individual CLA](https://developers.google.com/open-source/cla/individual).
+* If you work for a company that wants to allow you to contribute your work,
+then sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it.
+
+## Submitting a Patch
+
+1. Sign the contributors license agreement above.
+2. Decide which code you want to submit. A submission should be a set of changes
+that addresses one issue in the [issue tracker](https://github.com/google/leveldb/issues).
+Please don't mix more than one logical change per submission, because it makes
+the history hard to follow. If you want to make a change
+(e.g. add a sample or feature) that doesn't have a corresponding issue in the
+issue tracker, please create one.
+3. **Submitting**: When you are ready to submit, send us a Pull Request. Be
+sure to include the issue number you fixed and the name you used to sign
+the CLA.
+
+## Writing Code ##
+
+If your contribution contains code, please make sure that it follows
+[the style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml).
+Otherwise we will have to ask you to make changes, and that's no fun for anyone.
diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile
index f8903b69e4..2bd2cadcdd 100644
--- a/src/leveldb/Makefile
+++ b/src/leveldb/Makefile
@@ -6,9 +6,12 @@
# Uncomment exactly one of the lines labelled (A), (B), and (C) below
# to switch between compilation modes.
-OPT ?= -O2 -DNDEBUG # (A) Production use (optimized mode)
-# OPT ?= -g2 # (B) Debug mode, w/ full line-level debugging symbols
-# OPT ?= -O2 -g2 -DNDEBUG # (C) Profiling mode: opt, but w/debugging symbols
+# (A) Production use (optimized mode)
+OPT ?= -O2 -DNDEBUG
+# (B) Debug mode, w/ full line-level debugging symbols
+# OPT ?= -g2
+# (C) Profiling mode: opt, but w/debugging symbols
+# OPT ?= -O2 -g2 -DNDEBUG
#-----------------------------------------------
# detect what platform we're building on
@@ -29,6 +32,11 @@ MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o)
TESTUTIL = ./util/testutil.o
TESTHARNESS = ./util/testharness.o $(TESTUTIL)
+# Note: iOS should probably be using libtool, not ar.
+ifeq ($(PLATFORM), IOS)
+AR=xcrun ar
+endif
+
TESTS = \
arena_test \
autocompact_test \
@@ -43,6 +51,7 @@ TESTS = \
env_test \
filename_test \
filter_block_test \
+ hash_test \
issue178_test \
issue200_test \
log_test \
@@ -72,7 +81,7 @@ SHARED = $(SHARED1)
else
# Update db.h if you change these.
SHARED_MAJOR = 1
-SHARED_MINOR = 17
+SHARED_MINOR = 18
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
@@ -152,6 +161,9 @@ filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS)
filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+hash_test: util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
issue178_test: issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) $(LDFLAGS) issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
@@ -194,17 +206,17 @@ IOSARCH=-arch armv6 -arch armv7 -arch armv7s -arch arm64
.cc.o:
mkdir -p ios-x86/$(dir $@)
- $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@
+ xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@
mkdir -p ios-arm/$(dir $@)
xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@
- lipo ios-x86/$@ ios-arm/$@ -create -output $@
+ xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@
.c.o:
mkdir -p ios-x86/$(dir $@)
- $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@
+ xcrun -sdk iphonesimulator $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@
mkdir -p ios-arm/$(dir $@)
xcrun -sdk iphoneos $(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@
- lipo ios-x86/$@ ios-arm/$@ -create -output $@
+ xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@
else
.cc.o:
diff --git a/src/leveldb/README.md b/src/leveldb/README.md
new file mode 100644
index 0000000000..480affb5ca
--- /dev/null
+++ b/src/leveldb/README.md
@@ -0,0 +1,138 @@
+**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.**
+
+Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
+
+# Features
+ * Keys and values are arbitrary byte arrays.
+ * Data is stored sorted by key.
+ * Callers can provide a custom comparison function to override the sort order.
+ * The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`.
+ * Multiple changes can be made in one atomic batch.
+ * Users can create a transient snapshot to get a consistent view of data.
+ * Forward and backward iteration is supported over the data.
+ * Data is automatically compressed using the [Snappy compression library](http://code.google.com/p/snappy).
+ * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions.
+ * [Detailed documentation](http://htmlpreview.github.io/?https://github.com/google/leveldb/blob/master/doc/index.html) about how to use the library is included with the source code.
+
+
+# Limitations
+ * This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes.
+ * Only a single process (possibly multi-threaded) can access a particular database at a time.
+ * There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library.
+
+# Performance
+
+Here is a performance report (with explanations) from the run of the
+included db_bench program. The results are somewhat noisy, but should
+be enough to get a ballpark performance estimate.
+
+## Setup
+
+We use a database with a million entries. Each entry has a 16 byte
+key, and a 100 byte value. Values used by the benchmark compress to
+about half their original size.
+
+ LevelDB: version 1.1
+ Date: Sun May 1 12:11:26 2011
+ CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
+ CPUCache: 4096 KB
+ Keys: 16 bytes each
+ Values: 100 bytes each (50 bytes after compression)
+ Entries: 1000000
+ Raw Size: 110.6 MB (estimated)
+ File Size: 62.9 MB (estimated)
+
+## Write performance
+
+The "fill" benchmarks create a brand new database, in either
+sequential, or random order. The "fillsync" benchmark flushes data
+from the operating system to the disk after every operation; the other
+write operations leave the data sitting in the operating system buffer
+cache for a while. The "overwrite" benchmark does random writes that
+update existing keys in the database.
+
+ fillseq : 1.765 micros/op; 62.7 MB/s
+ fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops)
+ fillrandom : 2.460 micros/op; 45.0 MB/s
+ overwrite : 2.380 micros/op; 46.5 MB/s
+
+Each "op" above corresponds to a write of a single key/value pair.
+I.e., a random write benchmark goes at approximately 400,000 writes per second.
+
+Each "fillsync" operation costs much less (0.3 millisecond)
+than a disk seek (typically 10 milliseconds). We suspect that this is
+because the hard disk itself is buffering the update in its memory and
+responding before the data has been written to the platter. This may
+or may not be safe based on whether or not the hard disk has enough
+power to save its memory in the event of a power failure.
+
+## Read performance
+
+We list the performance of reading sequentially in both the forward
+and reverse direction, and also the performance of a random lookup.
+Note that the database created by the benchmark is quite small.
+Therefore the report characterizes the performance of leveldb when the
+working set fits in memory. The cost of reading a piece of data that
+is not present in the operating system buffer cache will be dominated
+by the one or two disk seeks needed to fetch the data from disk.
+Write performance will be mostly unaffected by whether or not the
+working set fits in memory.
+
+ readrandom : 16.677 micros/op; (approximately 60,000 reads per second)
+ readseq : 0.476 micros/op; 232.3 MB/s
+ readreverse : 0.724 micros/op; 152.9 MB/s
+
+LevelDB compacts its underlying storage data in the background to
+improve read performance. The results listed above were done
+immediately after a lot of random writes. The results after
+compactions (which are usually triggered automatically) are better.
+
+ readrandom : 11.602 micros/op; (approximately 85,000 reads per second)
+ readseq : 0.423 micros/op; 261.8 MB/s
+ readreverse : 0.663 micros/op; 166.9 MB/s
+
+Some of the high cost of reads comes from repeated decompression of blocks
+read from disk. If we supply enough cache to the leveldb so it can hold the
+uncompressed blocks in memory, the read performance improves again:
+
+ readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction)
+ readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction)
+
+## Repository contents
+
+See doc/index.html for more explanation. See doc/impl.html for a brief overview of the implementation.
+
+The public interface is in include/*.h. Callers should not include or
+rely on the details of any other header files in this package. Those
+internal APIs may be changed without warning.
+
+Guide to header files:
+
+* **include/db.h**: Main interface to the DB: Start here
+
+* **include/options.h**: Control over the behavior of an entire database,
+and also control over the behavior of individual reads and writes.
+
+* **include/comparator.h**: Abstraction for user-specified comparison function.
+If you want just bytewise comparison of keys, you can use the default
+comparator, but clients can write their own comparator implementations if they
+want custom ordering (e.g. to handle different character encodings, etc.)
+
+* **include/iterator.h**: Interface for iterating over data. You can get
+an iterator from a DB object.
+
+* **include/write_batch.h**: Interface for atomically applying multiple
+updates to a database.
+
+* **include/slice.h**: A simple module for maintaining a pointer and a
+length into some other byte array.
+
+* **include/status.h**: Status is returned from many of the public interfaces
+and is used to report success and various kinds of errors.
+
+* **include/env.h**:
+Abstraction of the OS environment. A posix implementation of this interface is
+in util/env_posix.cc
+
+* **include/table.h, include/table_builder.h**: Lower-level modules that most
+clients probably won't use directly
diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform
index 85b1ce0224..a1101c1bda 100755
--- a/src/leveldb/build_detect_platform
+++ b/src/leveldb/build_detect_platform
@@ -20,7 +20,7 @@
#
# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following:
#
-# -DLEVELDB_CSTDATOMIC_PRESENT if <cstdatomic> is present
+# -DLEVELDB_ATOMIC_PRESENT if <atomic> is present
# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms
# -DSNAPPY if the Snappy library is present
#
@@ -72,6 +72,12 @@ if [ "$CXX" = "g++" ]; then
fi
case "$TARGET_OS" in
+ CYGWIN_*)
+ PLATFORM=OS_LINUX
+ COMMON_FLAGS="$MEMCMP_FLAG -lpthread -DOS_LINUX -DCYGWIN"
+ PLATFORM_LDFLAGS="-lpthread"
+ PORT_FILE=port/port_posix.cc
+ ;;
Darwin)
PLATFORM=OS_MACOSX
COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX"
@@ -185,13 +191,14 @@ if [ "$CROSS_COMPILE" = "true" ]; then
else
CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$"
- # If -std=c++0x works, use <cstdatomic>. Otherwise use port_posix.h.
+ # If -std=c++0x works, use <atomic> as fallback for when memory barriers
+ # are not available.
$CXX $CXXFLAGS -std=c++0x -x c++ - -o $CXXOUTPUT 2>/dev/null <<EOF
- #include <cstdatomic>
+ #include <atomic>
int main() {}
EOF
if [ "$?" = 0 ]; then
- COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_CSTDATOMIC_PRESENT"
+ COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_ATOMIC_PRESENT"
PLATFORM_CXXFLAGS="-std=c++0x"
else
COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX"
diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc
index fc46d89693..705a170aae 100644
--- a/src/leveldb/db/db_bench.cc
+++ b/src/leveldb/db/db_bench.cc
@@ -431,7 +431,7 @@ class Benchmark {
benchmarks = sep + 1;
}
- // Reset parameters that may be overriddden bwlow
+ // Reset parameters that may be overridden below
num_ = FLAGS_num;
reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads);
value_size_ = FLAGS_value_size;
@@ -811,7 +811,6 @@ class Benchmark {
void SeekRandom(ThreadState* thread) {
ReadOptions options;
- std::string value;
int found = 0;
for (int i = 0; i < reads_; i++) {
Iterator* iter = db_->NewIterator(options);
diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc
index faf5e7d7ba..49b95953b4 100644
--- a/src/leveldb/db/db_impl.cc
+++ b/src/leveldb/db/db_impl.cc
@@ -392,7 +392,7 @@ Status DBImpl::RecoverLogFile(uint64_t log_number,
reporter.info_log = options_.info_log;
reporter.fname = fname.c_str();
reporter.status = (options_.paranoid_checks ? &status : NULL);
- // We intentially make log::Reader do checksumming even if
+ // We intentionally make log::Reader do checksumming even if
// paranoid_checks==false so that corruptions cause entire commits
// to be skipped instead of propagating bad information (like overly
// large sequence numbers).
@@ -1267,7 +1267,7 @@ WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {
break;
}
- // Append to *reuslt
+ // Append to *result
if (result == first->batch) {
// Switch to temporary batch instead of disturbing caller's batch
result = tmp_batch_;
diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc
index 280b01c14b..0fed9137d5 100644
--- a/src/leveldb/db/db_test.cc
+++ b/src/leveldb/db/db_test.cc
@@ -626,7 +626,7 @@ TEST(DBTest, GetEncountersEmptyLevel) {
// * sstable B in level 2
// Then do enough Get() calls to arrange for an automatic compaction
// of sstable A. A bug would cause the compaction to be marked as
- // occuring at level 1 (instead of the correct level 0).
+ // occurring at level 1 (instead of the correct level 0).
// Step 1: First place sstables in levels 0 and 2
int compaction_count = 0;
diff --git a/src/leveldb/db/dbformat.h b/src/leveldb/db/dbformat.h
index 5d8a032bd3..ea897b13c0 100644
--- a/src/leveldb/db/dbformat.h
+++ b/src/leveldb/db/dbformat.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
-#ifndef STORAGE_LEVELDB_DB_FORMAT_H_
-#define STORAGE_LEVELDB_DB_FORMAT_H_
+#ifndef STORAGE_LEVELDB_DB_DBFORMAT_H_
+#define STORAGE_LEVELDB_DB_DBFORMAT_H_
#include <stdio.h>
#include "leveldb/comparator.h"
@@ -227,4 +227,4 @@ inline LookupKey::~LookupKey() {
} // namespace leveldb
-#endif // STORAGE_LEVELDB_DB_FORMAT_H_
+#endif // STORAGE_LEVELDB_DB_DBFORMAT_H_
diff --git a/src/leveldb/db/dumpfile.cc b/src/leveldb/db/dumpfile.cc
new file mode 100644
index 0000000000..61c47c2ff9
--- /dev/null
+++ b/src/leveldb/db/dumpfile.cc
@@ -0,0 +1,225 @@
+// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#include <stdio.h>
+#include "db/dbformat.h"
+#include "db/filename.h"
+#include "db/log_reader.h"
+#include "db/version_edit.h"
+#include "db/write_batch_internal.h"
+#include "leveldb/env.h"
+#include "leveldb/iterator.h"
+#include "leveldb/options.h"
+#include "leveldb/status.h"
+#include "leveldb/table.h"
+#include "leveldb/write_batch.h"
+#include "util/logging.h"
+
+namespace leveldb {
+
+namespace {
+
+bool GuessType(const std::string& fname, FileType* type) {
+ size_t pos = fname.rfind('/');
+ std::string basename;
+ if (pos == std::string::npos) {
+ basename = fname;
+ } else {
+ basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);
+ }
+ uint64_t ignored;
+ return ParseFileName(basename, &ignored, type);
+}
+
+// Notified when log reader encounters corruption.
+class CorruptionReporter : public log::Reader::Reporter {
+ public:
+ WritableFile* dst_;
+ virtual void Corruption(size_t bytes, const Status& status) {
+ std::string r = "corruption: ";
+ AppendNumberTo(&r, bytes);
+ r += " bytes; ";
+ r += status.ToString();
+ r.push_back('\n');
+ dst_->Append(r);
+ }
+};
+
+// Print contents of a log file. (*func)() is called on every record.
+Status PrintLogContents(Env* env, const std::string& fname,
+ void (*func)(uint64_t, Slice, WritableFile*),
+ WritableFile* dst) {
+ SequentialFile* file;
+ Status s = env->NewSequentialFile(fname, &file);
+ if (!s.ok()) {
+ return s;
+ }
+ CorruptionReporter reporter;
+ reporter.dst_ = dst;
+ log::Reader reader(file, &reporter, true, 0);
+ Slice record;
+ std::string scratch;
+ while (reader.ReadRecord(&record, &scratch)) {
+ (*func)(reader.LastRecordOffset(), record, dst);
+ }
+ delete file;
+ return Status::OK();
+}
+
+// Called on every item found in a WriteBatch.
+class WriteBatchItemPrinter : public WriteBatch::Handler {
+ public:
+ WritableFile* dst_;
+ virtual void Put(const Slice& key, const Slice& value) {
+ std::string r = " put '";
+ AppendEscapedStringTo(&r, key);
+ r += "' '";
+ AppendEscapedStringTo(&r, value);
+ r += "'\n";
+ dst_->Append(r);
+ }
+ virtual void Delete(const Slice& key) {
+ std::string r = " del '";
+ AppendEscapedStringTo(&r, key);
+ r += "'\n";
+ dst_->Append(r);
+ }
+};
+
+
+// Called on every log record (each one of which is a WriteBatch)
+// found in a kLogFile.
+static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) {
+ std::string r = "--- offset ";
+ AppendNumberTo(&r, pos);
+ r += "; ";
+ if (record.size() < 12) {
+ r += "log record length ";
+ AppendNumberTo(&r, record.size());
+ r += " is too small\n";
+ dst->Append(r);
+ return;
+ }
+ WriteBatch batch;
+ WriteBatchInternal::SetContents(&batch, record);
+ r += "sequence ";
+ AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));
+ r.push_back('\n');
+ dst->Append(r);
+ WriteBatchItemPrinter batch_item_printer;
+ batch_item_printer.dst_ = dst;
+ Status s = batch.Iterate(&batch_item_printer);
+ if (!s.ok()) {
+ dst->Append(" error: " + s.ToString() + "\n");
+ }
+}
+
+Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) {
+ return PrintLogContents(env, fname, WriteBatchPrinter, dst);
+}
+
+// Called on every log record (each one of which is a WriteBatch)
+// found in a kDescriptorFile.
+static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) {
+ std::string r = "--- offset ";
+ AppendNumberTo(&r, pos);
+ r += "; ";
+ VersionEdit edit;
+ Status s = edit.DecodeFrom(record);
+ if (!s.ok()) {
+ r += s.ToString();
+ r.push_back('\n');
+ } else {
+ r += edit.DebugString();
+ }
+ dst->Append(r);
+}
+
+Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) {
+ return PrintLogContents(env, fname, VersionEditPrinter, dst);
+}
+
+Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) {
+ uint64_t file_size;
+ RandomAccessFile* file = NULL;
+ Table* table = NULL;
+ Status s = env->GetFileSize(fname, &file_size);
+ if (s.ok()) {
+ s = env->NewRandomAccessFile(fname, &file);
+ }
+ if (s.ok()) {
+ // We use the default comparator, which may or may not match the
+ // comparator used in this database. However this should not cause
+ // problems since we only use Table operations that do not require
+ // any comparisons. In particular, we do not call Seek or Prev.
+ s = Table::Open(Options(), file, file_size, &table);
+ }
+ if (!s.ok()) {
+ delete table;
+ delete file;
+ return s;
+ }
+
+ ReadOptions ro;
+ ro.fill_cache = false;
+ Iterator* iter = table->NewIterator(ro);
+ std::string r;
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
+ r.clear();
+ ParsedInternalKey key;
+ if (!ParseInternalKey(iter->key(), &key)) {
+ r = "badkey '";
+ AppendEscapedStringTo(&r, iter->key());
+ r += "' => '";
+ AppendEscapedStringTo(&r, iter->value());
+ r += "'\n";
+ dst->Append(r);
+ } else {
+ r = "'";
+ AppendEscapedStringTo(&r, key.user_key);
+ r += "' @ ";
+ AppendNumberTo(&r, key.sequence);
+ r += " : ";
+ if (key.type == kTypeDeletion) {
+ r += "del";
+ } else if (key.type == kTypeValue) {
+ r += "val";
+ } else {
+ AppendNumberTo(&r, key.type);
+ }
+ r += " => '";
+ AppendEscapedStringTo(&r, iter->value());
+ r += "'\n";
+ dst->Append(r);
+ }
+ }
+ s = iter->status();
+ if (!s.ok()) {
+ dst->Append("iterator error: " + s.ToString() + "\n");
+ }
+
+ delete iter;
+ delete table;
+ delete file;
+ return Status::OK();
+}
+
+} // namespace
+
+Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) {
+ FileType ftype;
+ if (!GuessType(fname, &ftype)) {
+ return Status::InvalidArgument(fname + ": unknown file type");
+ }
+ switch (ftype) {
+ case kLogFile: return DumpLog(env, fname, dst);
+ case kDescriptorFile: return DumpDescriptor(env, fname, dst);
+ case kTableFile: return DumpTable(env, fname, dst);
+ default:
+ break;
+ }
+ return Status::InvalidArgument(fname + ": not a dump-able file type");
+}
+
+} // namespace leveldb
diff --git a/src/leveldb/db/leveldb_main.cc b/src/leveldb/db/leveldb_main.cc
index 995d76107a..9f4b7dd70c 100644
--- a/src/leveldb/db/leveldb_main.cc
+++ b/src/leveldb/db/leveldb_main.cc
@@ -3,212 +3,38 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <stdio.h>
-#include "db/dbformat.h"
-#include "db/filename.h"
-#include "db/log_reader.h"
-#include "db/version_edit.h"
-#include "db/write_batch_internal.h"
+#include "leveldb/dumpfile.h"
#include "leveldb/env.h"
-#include "leveldb/iterator.h"
-#include "leveldb/options.h"
#include "leveldb/status.h"
-#include "leveldb/table.h"
-#include "leveldb/write_batch.h"
-#include "util/logging.h"
namespace leveldb {
-
namespace {
-bool GuessType(const std::string& fname, FileType* type) {
- size_t pos = fname.rfind('/');
- std::string basename;
- if (pos == std::string::npos) {
- basename = fname;
- } else {
- basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);
- }
- uint64_t ignored;
- return ParseFileName(basename, &ignored, type);
-}
-
-// Notified when log reader encounters corruption.
-class CorruptionReporter : public log::Reader::Reporter {
- public:
- virtual void Corruption(size_t bytes, const Status& status) {
- printf("corruption: %d bytes; %s\n",
- static_cast<int>(bytes),
- status.ToString().c_str());
- }
-};
-
-// Print contents of a log file. (*func)() is called on every record.
-bool PrintLogContents(Env* env, const std::string& fname,
- void (*func)(Slice)) {
- SequentialFile* file;
- Status s = env->NewSequentialFile(fname, &file);
- if (!s.ok()) {
- fprintf(stderr, "%s\n", s.ToString().c_str());
- return false;
- }
- CorruptionReporter reporter;
- log::Reader reader(file, &reporter, true, 0);
- Slice record;
- std::string scratch;
- while (reader.ReadRecord(&record, &scratch)) {
- printf("--- offset %llu; ",
- static_cast<unsigned long long>(reader.LastRecordOffset()));
- (*func)(record);
- }
- delete file;
- return true;
-}
-
-// Called on every item found in a WriteBatch.
-class WriteBatchItemPrinter : public WriteBatch::Handler {
+class StdoutPrinter : public WritableFile {
public:
- uint64_t offset_;
- uint64_t sequence_;
-
- virtual void Put(const Slice& key, const Slice& value) {
- printf(" put '%s' '%s'\n",
- EscapeString(key).c_str(),
- EscapeString(value).c_str());
- }
- virtual void Delete(const Slice& key) {
- printf(" del '%s'\n",
- EscapeString(key).c_str());
+ virtual Status Append(const Slice& data) {
+ fwrite(data.data(), 1, data.size(), stdout);
+ return Status::OK();
}
+ virtual Status Close() { return Status::OK(); }
+ virtual Status Flush() { return Status::OK(); }
+ virtual Status Sync() { return Status::OK(); }
};
-
-// Called on every log record (each one of which is a WriteBatch)
-// found in a kLogFile.
-static void WriteBatchPrinter(Slice record) {
- if (record.size() < 12) {
- printf("log record length %d is too small\n",
- static_cast<int>(record.size()));
- return;
- }
- WriteBatch batch;
- WriteBatchInternal::SetContents(&batch, record);
- printf("sequence %llu\n",
- static_cast<unsigned long long>(WriteBatchInternal::Sequence(&batch)));
- WriteBatchItemPrinter batch_item_printer;
- Status s = batch.Iterate(&batch_item_printer);
- if (!s.ok()) {
- printf(" error: %s\n", s.ToString().c_str());
- }
-}
-
-bool DumpLog(Env* env, const std::string& fname) {
- return PrintLogContents(env, fname, WriteBatchPrinter);
-}
-
-// Called on every log record (each one of which is a WriteBatch)
-// found in a kDescriptorFile.
-static void VersionEditPrinter(Slice record) {
- VersionEdit edit;
- Status s = edit.DecodeFrom(record);
- if (!s.ok()) {
- printf("%s\n", s.ToString().c_str());
- return;
- }
- printf("%s", edit.DebugString().c_str());
-}
-
-bool DumpDescriptor(Env* env, const std::string& fname) {
- return PrintLogContents(env, fname, VersionEditPrinter);
-}
-
-bool DumpTable(Env* env, const std::string& fname) {
- uint64_t file_size;
- RandomAccessFile* file = NULL;
- Table* table = NULL;
- Status s = env->GetFileSize(fname, &file_size);
- if (s.ok()) {
- s = env->NewRandomAccessFile(fname, &file);
- }
- if (s.ok()) {
- // We use the default comparator, which may or may not match the
- // comparator used in this database. However this should not cause
- // problems since we only use Table operations that do not require
- // any comparisons. In particular, we do not call Seek or Prev.
- s = Table::Open(Options(), file, file_size, &table);
- }
- if (!s.ok()) {
- fprintf(stderr, "%s\n", s.ToString().c_str());
- delete table;
- delete file;
- return false;
- }
-
- ReadOptions ro;
- ro.fill_cache = false;
- Iterator* iter = table->NewIterator(ro);
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- ParsedInternalKey key;
- if (!ParseInternalKey(iter->key(), &key)) {
- printf("badkey '%s' => '%s'\n",
- EscapeString(iter->key()).c_str(),
- EscapeString(iter->value()).c_str());
- } else {
- char kbuf[20];
- const char* type;
- if (key.type == kTypeDeletion) {
- type = "del";
- } else if (key.type == kTypeValue) {
- type = "val";
- } else {
- snprintf(kbuf, sizeof(kbuf), "%d", static_cast<int>(key.type));
- type = kbuf;
- }
- printf("'%s' @ %8llu : %s => '%s'\n",
- EscapeString(key.user_key).c_str(),
- static_cast<unsigned long long>(key.sequence),
- type,
- EscapeString(iter->value()).c_str());
- }
- }
- s = iter->status();
- if (!s.ok()) {
- printf("iterator error: %s\n", s.ToString().c_str());
- }
-
- delete iter;
- delete table;
- delete file;
- return true;
-}
-
-bool DumpFile(Env* env, const std::string& fname) {
- FileType ftype;
- if (!GuessType(fname, &ftype)) {
- fprintf(stderr, "%s: unknown file type\n", fname.c_str());
- return false;
- }
- switch (ftype) {
- case kLogFile: return DumpLog(env, fname);
- case kDescriptorFile: return DumpDescriptor(env, fname);
- case kTableFile: return DumpTable(env, fname);
-
- default: {
- fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str());
- break;
- }
- }
- return false;
-}
-
bool HandleDumpCommand(Env* env, char** files, int num) {
+ StdoutPrinter printer;
bool ok = true;
for (int i = 0; i < num; i++) {
- ok &= DumpFile(env, files[i]);
+ Status s = DumpFile(env, files[i], &printer);
+ if (!s.ok()) {
+ fprintf(stderr, "%s\n", s.ToString().c_str());
+ ok = false;
+ }
}
return ok;
}
-}
+} // namespace
} // namespace leveldb
static void Usage() {
diff --git a/src/leveldb/db/log_format.h b/src/leveldb/db/log_format.h
index 2690cb9789..a8c06efe18 100644
--- a/src/leveldb/db/log_format.h
+++ b/src/leveldb/db/log_format.h
@@ -26,8 +26,8 @@ static const int kMaxRecordType = kLastType;
static const int kBlockSize = 32768;
-// Header is checksum (4 bytes), type (1 byte), length (2 bytes).
-static const int kHeaderSize = 4 + 1 + 2;
+// Header is checksum (4 bytes), length (2 bytes), type (1 byte).
+static const int kHeaderSize = 4 + 2 + 1;
} // namespace log
} // namespace leveldb
diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc
index 4919216d04..e44b66c85b 100644
--- a/src/leveldb/db/log_reader.cc
+++ b/src/leveldb/db/log_reader.cc
@@ -167,14 +167,14 @@ uint64_t Reader::LastRecordOffset() {
return last_record_offset_;
}
-void Reader::ReportCorruption(size_t bytes, const char* reason) {
+void Reader::ReportCorruption(uint64_t bytes, const char* reason) {
ReportDrop(bytes, Status::Corruption(reason));
}
-void Reader::ReportDrop(size_t bytes, const Status& reason) {
+void Reader::ReportDrop(uint64_t bytes, const Status& reason) {
if (reporter_ != NULL &&
end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) {
- reporter_->Corruption(bytes, reason);
+ reporter_->Corruption(static_cast<size_t>(bytes), reason);
}
}
diff --git a/src/leveldb/db/log_reader.h b/src/leveldb/db/log_reader.h
index 82d4bee68d..6aff791716 100644
--- a/src/leveldb/db/log_reader.h
+++ b/src/leveldb/db/log_reader.h
@@ -94,8 +94,8 @@ class Reader {
// Reports dropped bytes to the reporter.
// buffer_ must be updated to remove the dropped bytes prior to invocation.
- void ReportCorruption(size_t bytes, const char* reason);
- void ReportDrop(size_t bytes, const Status& reason);
+ void ReportCorruption(uint64_t bytes, const char* reason);
+ void ReportDrop(uint64_t bytes, const Status& reason);
// No copying allowed
Reader(const Reader&);
diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc
index 91d3caafc3..dcf0562652 100644
--- a/src/leveldb/db/log_test.cc
+++ b/src/leveldb/db/log_test.cc
@@ -463,7 +463,7 @@ TEST(LogTest, ErrorJoinsRecords) {
ASSERT_EQ("correct", Read());
ASSERT_EQ("EOF", Read());
- const int dropped = DroppedBytes();
+ const size_t dropped = DroppedBytes();
ASSERT_LE(dropped, 2*kBlockSize + 100);
ASSERT_GE(dropped, 2*kBlockSize);
}
diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc
index 7727fafc58..4cd4bb047f 100644
--- a/src/leveldb/db/repair.cc
+++ b/src/leveldb/db/repair.cc
@@ -186,7 +186,7 @@ class Repairer {
reporter.env = env_;
reporter.info_log = options_.info_log;
reporter.lognum = log;
- // We intentially make log::Reader do checksumming so that
+ // We intentionally make log::Reader do checksumming so that
// corruptions cause entire commits to be skipped instead of
// propagating bad information (like overly large sequence
// numbers).
diff --git a/src/leveldb/db/skiplist.h b/src/leveldb/db/skiplist.h
index af85be6d01..ed8b092203 100644
--- a/src/leveldb/db/skiplist.h
+++ b/src/leveldb/db/skiplist.h
@@ -1,3 +1,6 @@
+#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_
+#define STORAGE_LEVELDB_DB_SKIPLIST_H_
+
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
@@ -377,3 +380,5 @@ bool SkipList<Key,Comparator>::Contains(const Key& key) const {
}
} // namespace leveldb
+
+#endif // STORAGE_LEVELDB_DB_SKIPLIST_H_
diff --git a/src/leveldb/db/write_batch_internal.h b/src/leveldb/db/write_batch_internal.h
index 4423a7f318..310a3c8912 100644
--- a/src/leveldb/db/write_batch_internal.h
+++ b/src/leveldb/db/write_batch_internal.h
@@ -21,10 +21,10 @@ class WriteBatchInternal {
// Set the count for the number of entries in the batch.
static void SetCount(WriteBatch* batch, int n);
- // Return the seqeunce number for the start of this batch.
+ // Return the sequence number for the start of this batch.
static SequenceNumber Sequence(const WriteBatch* batch);
- // Store the specified number as the seqeunce number for the start of
+ // Store the specified number as the sequence number for the start of
// this batch.
static void SetSequence(WriteBatch* batch, SequenceNumber seq);
diff --git a/src/leveldb/doc/bench/db_bench_tree_db.cc b/src/leveldb/doc/bench/db_bench_tree_db.cc
index ed86f031c2..4ca381f11f 100644
--- a/src/leveldb/doc/bench/db_bench_tree_db.cc
+++ b/src/leveldb/doc/bench/db_bench_tree_db.cc
@@ -338,7 +338,7 @@ class Benchmark {
bool write_sync = false;
if (name == Slice("fillseq")) {
Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1);
-
+ DBSynchronize(db_);
} else if (name == Slice("fillrandom")) {
Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1);
DBSynchronize(db_);
diff --git a/src/leveldb/doc/impl.html b/src/leveldb/doc/impl.html
index 28817fe0da..6a468be095 100644
--- a/src/leveldb/doc/impl.html
+++ b/src/leveldb/doc/impl.html
@@ -111,7 +111,7 @@ A compaction merges the contents of the picked files to produce a
sequence of level-(L+1) files. We switch to producing a new
level-(L+1) file after the current output file has reached the target
file size (2MB). We also switch to a new output file when the key
-range of the current output file has grown enough to overlap more then
+range of the current output file has grown enough to overlap more than
ten level-(L+2) files. This last rule ensures that a later compaction
of a level-(L+1) file will not pick up too much data from level-(L+2).
@@ -151,7 +151,7 @@ compaction cost will be approximately 0.5 second.
If we throttle the background writing to something small, say 10% of
the full 100MB/s speed, a compaction may take up to 5 seconds. If the
user is writing at 10MB/s, we might build up lots of level-0 files
-(~50 to hold the 5*10MB). This may signficantly increase the cost of
+(~50 to hold the 5*10MB). This may significantly increase the cost of
reads due to the overhead of merging more files together on every
read.
diff --git a/src/leveldb/doc/log_format.txt b/src/leveldb/doc/log_format.txt
index 5228f624de..4cca5ef6ea 100644
--- a/src/leveldb/doc/log_format.txt
+++ b/src/leveldb/doc/log_format.txt
@@ -11,7 +11,7 @@ Each block consists of a sequence of records:
A record never starts within the last six bytes of a block (since it
won't fit). Any leftover bytes here form the trailer, which must
-consist entirely of zero bytes and must be skipped by readers.
+consist entirely of zero bytes and must be skipped by readers.
Aside: if exactly seven bytes are left in the current block, and a new
non-zero length record is added, the writer must emit a FIRST record
@@ -33,8 +33,8 @@ The FULL record contains the contents of an entire user record.
FIRST, MIDDLE, LAST are types used for user records that have been
split into multiple fragments (typically because of block boundaries).
FIRST is the type of the first fragment of a user record, LAST is the
-type of the last fragment of a user record, and MID is the type of all
-interior fragments of a user record.
+type of the last fragment of a user record, and MIDDLE is the type of
+all interior fragments of a user record.
Example: consider a sequence of user records:
A: length 1000
diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc
index 5879de1214..43ef2e0729 100644
--- a/src/leveldb/helpers/memenv/memenv.cc
+++ b/src/leveldb/helpers/memenv/memenv.cc
@@ -55,14 +55,15 @@ class FileState {
}
const uint64_t available = size_ - offset;
if (n > available) {
- n = available;
+ n = static_cast<size_t>(available);
}
if (n == 0) {
*result = Slice();
return Status::OK();
}
- size_t block = offset / kBlockSize;
+ assert(offset / kBlockSize <= SIZE_MAX);
+ size_t block = static_cast<size_t>(offset / kBlockSize);
size_t block_offset = offset % kBlockSize;
if (n <= kBlockSize - block_offset) {
@@ -167,7 +168,7 @@ class SequentialFileImpl : public SequentialFile {
if (pos_ > file_->Size()) {
return Status::IOError("pos_ > file_->Size()");
}
- const size_t available = file_->Size() - pos_;
+ const uint64_t available = file_->Size() - pos_;
if (n > available) {
n = available;
}
@@ -177,7 +178,7 @@ class SequentialFileImpl : public SequentialFile {
private:
FileState* file_;
- size_t pos_;
+ uint64_t pos_;
};
class RandomAccessFileImpl : public RandomAccessFile {
diff --git a/src/leveldb/include/leveldb/cache.h b/src/leveldb/include/leveldb/cache.h
index 5e3b47637d..1a201e5e0a 100644
--- a/src/leveldb/include/leveldb/cache.h
+++ b/src/leveldb/include/leveldb/cache.h
@@ -96,4 +96,4 @@ class Cache {
} // namespace leveldb
-#endif // STORAGE_LEVELDB_UTIL_CACHE_H_
+#endif // STORAGE_LEVELDB_INCLUDE_CACHE_H_
diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h
index 40851b2aa8..4c169bf22e 100644
--- a/src/leveldb/include/leveldb/db.h
+++ b/src/leveldb/include/leveldb/db.h
@@ -14,7 +14,7 @@ namespace leveldb {
// Update Makefile if you change these
static const int kMajorVersion = 1;
-static const int kMinorVersion = 17;
+static const int kMinorVersion = 18;
struct Options;
struct ReadOptions;
diff --git a/src/leveldb/include/leveldb/dumpfile.h b/src/leveldb/include/leveldb/dumpfile.h
new file mode 100644
index 0000000000..3f97fda16b
--- /dev/null
+++ b/src/leveldb/include/leveldb/dumpfile.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2014 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_
+#define STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_
+
+#include <string>
+#include "leveldb/env.h"
+#include "leveldb/status.h"
+
+namespace leveldb {
+
+// Dump the contents of the file named by fname in text format to
+// *dst. Makes a sequence of dst->Append() calls; each call is passed
+// the newline-terminated text corresponding to a single item found
+// in the file.
+//
+// Returns a non-OK result if fname does not name a leveldb storage
+// file, or if the file cannot be read.
+Status DumpFile(Env* env, const std::string& fname, WritableFile* dst);
+
+} // namespace leveldb
+
+#endif // STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_
diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h
index b2072d02c1..f709514da6 100644
--- a/src/leveldb/include/leveldb/env.h
+++ b/src/leveldb/include/leveldb/env.h
@@ -142,7 +142,7 @@ class Env {
// useful for computing deltas of time.
virtual uint64_t NowMicros() = 0;
- // Sleep/delay the thread for the perscribed number of micro-seconds.
+ // Sleep/delay the thread for the prescribed number of micro-seconds.
virtual void SleepForMicroseconds(int micros) = 0;
private:
diff --git a/src/leveldb/include/leveldb/iterator.h b/src/leveldb/include/leveldb/iterator.h
index ad543eb46c..76aced04bd 100644
--- a/src/leveldb/include/leveldb/iterator.h
+++ b/src/leveldb/include/leveldb/iterator.h
@@ -61,7 +61,7 @@ class Iterator {
// Return the value for the current entry. The underlying storage for
// the returned slice is valid only until the next modification of
// the iterator.
- // REQUIRES: !AtEnd() && !AtStart()
+ // REQUIRES: Valid()
virtual Slice value() const = 0;
// If an error has occurred, return it. Else return an ok status.
diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h
index fdda718d30..7c9b973454 100644
--- a/src/leveldb/include/leveldb/options.h
+++ b/src/leveldb/include/leveldb/options.h
@@ -153,7 +153,7 @@ struct ReadOptions {
// If "snapshot" is non-NULL, read as of the supplied snapshot
// (which must belong to the DB that is being read and which must
- // not have been released). If "snapshot" is NULL, use an impliicit
+ // not have been released). If "snapshot" is NULL, use an implicit
// snapshot of the state at the beginning of this read operation.
// Default: NULL
const Snapshot* snapshot;
diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h
index a9866b2302..9bf091f757 100644
--- a/src/leveldb/port/atomic_pointer.h
+++ b/src/leveldb/port/atomic_pointer.h
@@ -5,14 +5,13 @@
// AtomicPointer provides storage for a lock-free pointer.
// Platform-dependent implementation of AtomicPointer:
// - If the platform provides a cheap barrier, we use it with raw pointers
-// - If cstdatomic is present (on newer versions of gcc, it is), we use
-// a cstdatomic-based AtomicPointer. However we prefer the memory
+// - If <atomic> is present (on newer versions of gcc, it is), we use
+// a <atomic>-based AtomicPointer. However we prefer the memory
// barrier based version, because at least on a gcc 4.4 32-bit build
-// on linux, we have encountered a buggy <cstdatomic>
-// implementation. Also, some <cstdatomic> implementations are much
-// slower than a memory-barrier based implementation (~16ns for
-// <cstdatomic> based acquire-load vs. ~1ns for a barrier based
-// acquire-load).
+// on linux, we have encountered a buggy <atomic> implementation.
+// Also, some <atomic> implementations are much slower than a memory-barrier
+// based implementation (~16ns for <atomic> based acquire-load vs. ~1ns for
+// a barrier based acquire-load).
// This code is based on atomicops-internals-* in Google's perftools:
// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase
@@ -20,8 +19,8 @@
#define PORT_ATOMIC_POINTER_H_
#include <stdint.h>
-#ifdef LEVELDB_CSTDATOMIC_PRESENT
-#include <cstdatomic>
+#ifdef LEVELDB_ATOMIC_PRESENT
+#include <atomic>
#endif
#ifdef OS_WIN
#include <windows.h>
@@ -126,7 +125,7 @@ class AtomicPointer {
};
// AtomicPointer based on <cstdatomic>
-#elif defined(LEVELDB_CSTDATOMIC_PRESENT)
+#elif defined(LEVELDB_ATOMIC_PRESENT)
class AtomicPointer {
private:
std::atomic<void*> rep_;
@@ -207,7 +206,7 @@ class AtomicPointer {
inline void NoBarrier_Store(void* v) { rep_ = v; }
};
-// We have neither MemoryBarrier(), nor <cstdatomic>
+// We have neither MemoryBarrier(), nor <atomic>
#else
#error Please implement AtomicPointer for this platform.
diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h
index 21c845e211..ccca9939d3 100644
--- a/src/leveldb/port/port_posix.h
+++ b/src/leveldb/port/port_posix.h
@@ -21,14 +21,11 @@
#else
#define PLATFORM_IS_LITTLE_ENDIAN false
#endif
-#elif defined(OS_FREEBSD)
+#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) ||\
+ defined(OS_NETBSD) || defined(OS_DRAGONFLYBSD)
#include <sys/types.h>
#include <sys/endian.h>
#define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
-#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
- defined(OS_DRAGONFLYBSD)
- #include <sys/types.h>
- #include <sys/endian.h>
#elif defined(OS_HPUX)
#define PLATFORM_IS_LITTLE_ENDIAN false
#elif defined(OS_ANDROID)
@@ -55,7 +52,7 @@
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
- defined(OS_ANDROID) || defined(OS_HPUX)
+ defined(OS_ANDROID) || defined(OS_HPUX) || defined(CYGWIN)
// Use fread/fwrite/fflush on platforms without _unlocked variants
#define fread_unlocked fread
#define fwrite_unlocked fwrite
diff --git a/src/leveldb/port/thread_annotations.h b/src/leveldb/port/thread_annotations.h
index 6f9b6a7924..9470ef587c 100644
--- a/src/leveldb/port/thread_annotations.h
+++ b/src/leveldb/port/thread_annotations.h
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
-#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H
+#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_
+#define STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_
// Some environments provide custom macros to aid in static thread-safety
// analysis. Provide empty definitions of such macros unless they are already
@@ -56,4 +57,4 @@
#define NO_THREAD_SAFETY_ANALYSIS
#endif
-#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H
+#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_
diff --git a/src/leveldb/table/block.cc b/src/leveldb/table/block.cc
index 79ea9d9ee5..43e402c9c0 100644
--- a/src/leveldb/table/block.cc
+++ b/src/leveldb/table/block.cc
@@ -46,7 +46,7 @@ Block::~Block() {
// Helper routine: decode the next block entry starting at "p",
// storing the number of shared key bytes, non_shared key bytes,
// and the length of the value in "*shared", "*non_shared", and
-// "*value_length", respectively. Will not derefence past "limit".
+// "*value_length", respectively. Will not dereference past "limit".
//
// If any errors are detected, returns NULL. Otherwise, returns a
// pointer to the key delta (just past the three decoded values).
diff --git a/src/leveldb/table/block_builder.h b/src/leveldb/table/block_builder.h
index 5b545bd1af..4fbcb33972 100644
--- a/src/leveldb/table/block_builder.h
+++ b/src/leveldb/table/block_builder.h
@@ -21,7 +21,7 @@ class BlockBuilder {
// Reset the contents as if the BlockBuilder was just constructed.
void Reset();
- // REQUIRES: Finish() has not been callled since the last call to Reset().
+ // REQUIRES: Finish() has not been called since the last call to Reset().
// REQUIRES: key is larger than any previously added key
void Add(const Slice& key, const Slice& value);
diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc
index cda1decdf3..aa63144c9e 100644
--- a/src/leveldb/table/format.cc
+++ b/src/leveldb/table/format.cc
@@ -48,7 +48,7 @@ Status Footer::DecodeFrom(Slice* input) {
const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) |
(static_cast<uint64_t>(magic_lo)));
if (magic != kTableMagicNumber) {
- return Status::InvalidArgument("not an sstable (bad magic number)");
+ return Status::Corruption("not an sstable (bad magic number)");
}
Status result = metaindex_handle_.DecodeFrom(input);
diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc
index 71c1756e5f..dff8a82590 100644
--- a/src/leveldb/table/table.cc
+++ b/src/leveldb/table/table.cc
@@ -41,7 +41,7 @@ Status Table::Open(const Options& options,
Table** table) {
*table = NULL;
if (size < Footer::kEncodedLength) {
- return Status::InvalidArgument("file is too short to be an sstable");
+ return Status::Corruption("file is too short to be an sstable");
}
char footer_space[Footer::kEncodedLength];
@@ -58,7 +58,11 @@ Status Table::Open(const Options& options,
BlockContents contents;
Block* index_block = NULL;
if (s.ok()) {
- s = ReadBlock(file, ReadOptions(), footer.index_handle(), &contents);
+ ReadOptions opt;
+ if (options.paranoid_checks) {
+ opt.verify_checksums = true;
+ }
+ s = ReadBlock(file, opt, footer.index_handle(), &contents);
if (s.ok()) {
index_block = new Block(contents);
}
@@ -92,6 +96,9 @@ void Table::ReadMeta(const Footer& footer) {
// TODO(sanjay): Skip this if footer.metaindex_handle() size indicates
// it is an empty block.
ReadOptions opt;
+ if (rep_->options.paranoid_checks) {
+ opt.verify_checksums = true;
+ }
BlockContents contents;
if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) {
// Do not propagate errors since meta info is not needed for operation
@@ -120,6 +127,9 @@ void Table::ReadFilter(const Slice& filter_handle_value) {
// We might want to unify with ReadBlock() if we start
// requiring checksum verification in Table::Open.
ReadOptions opt;
+ if (rep_->options.paranoid_checks) {
+ opt.verify_checksums = true;
+ }
BlockContents block;
if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) {
return;
diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc
index d7941cd21f..a27a2ace28 100644
--- a/src/leveldb/util/bloom.cc
+++ b/src/leveldb/util/bloom.cc
@@ -29,7 +29,7 @@ class BloomFilterPolicy : public FilterPolicy {
}
virtual const char* Name() const {
- return "leveldb.BuiltinBloomFilter";
+ return "leveldb.BuiltinBloomFilter2";
}
virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const {
diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc
index 93eadb1a4f..ba2667864a 100644
--- a/src/leveldb/util/env_posix.cc
+++ b/src/leveldb/util/env_posix.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#if !defined(LEVELDB_PLATFORM_WINDOWS)
-#include <deque>
-#include <set>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -18,9 +16,8 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
-#if defined(LEVELDB_PLATFORM_ANDROID)
-#include <sys/stat.h>
-#endif
+#include <deque>
+#include <set>
#include "leveldb/env.h"
#include "leveldb/slice.h"
#include "port/port.h"
@@ -296,7 +293,8 @@ class PosixEnv : public Env {
public:
PosixEnv();
virtual ~PosixEnv() {
- fprintf(stderr, "Destroying Env::Default()\n");
+ char msg[] = "Destroying Env::Default()\n";
+ fwrite(msg, 1, sizeof(msg), stderr);
abort();
}
diff --git a/src/leveldb/util/hash.cc b/src/leveldb/util/hash.cc
index 07cf022060..ed439ce7a2 100644
--- a/src/leveldb/util/hash.cc
+++ b/src/leveldb/util/hash.cc
@@ -34,13 +34,13 @@ uint32_t Hash(const char* data, size_t n, uint32_t seed) {
// Pick up remaining bytes
switch (limit - data) {
case 3:
- h += data[2] << 16;
+ h += static_cast<unsigned char>(data[2]) << 16;
FALLTHROUGH_INTENDED;
case 2:
- h += data[1] << 8;
+ h += static_cast<unsigned char>(data[1]) << 8;
FALLTHROUGH_INTENDED;
case 1:
- h += data[0];
+ h += static_cast<unsigned char>(data[0]);
h *= m;
h ^= (h >> r);
break;
diff --git a/src/leveldb/util/hash_test.cc b/src/leveldb/util/hash_test.cc
new file mode 100644
index 0000000000..eaa1c92c23
--- /dev/null
+++ b/src/leveldb/util/hash_test.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#include "util/hash.h"
+#include "util/testharness.h"
+
+namespace leveldb {
+
+class HASH { };
+
+TEST(HASH, SignedUnsignedIssue) {
+ const unsigned char data1[1] = {0x62};
+ const unsigned char data2[2] = {0xc3, 0x97};
+ const unsigned char data3[3] = {0xe2, 0x99, 0xa5};
+ const unsigned char data4[4] = {0xe1, 0x80, 0xb9, 0x32};
+ const unsigned char data5[48] = {
+ 0x01, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x14,
+ 0x00, 0x00, 0x00, 0x18,
+ 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ };
+
+ ASSERT_EQ(Hash(0, 0, 0xbc9f1d34), 0xbc9f1d34);
+ ASSERT_EQ(
+ Hash(reinterpret_cast<const char*>(data1), sizeof(data1), 0xbc9f1d34),
+ 0xef1345c4);
+ ASSERT_EQ(
+ Hash(reinterpret_cast<const char*>(data2), sizeof(data2), 0xbc9f1d34),
+ 0x5b663814);
+ ASSERT_EQ(
+ Hash(reinterpret_cast<const char*>(data3), sizeof(data3), 0xbc9f1d34),
+ 0x323c078f);
+ ASSERT_EQ(
+ Hash(reinterpret_cast<const char*>(data4), sizeof(data4), 0xbc9f1d34),
+ 0xed21633a);
+ ASSERT_EQ(
+ Hash(reinterpret_cast<const char*>(data5), sizeof(data5), 0x12345678),
+ 0xf333dabb);
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ return leveldb::test::RunAllTests();
+}
diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc
index 22cf278512..ca6b324403 100644
--- a/src/leveldb/util/logging.cc
+++ b/src/leveldb/util/logging.cc
@@ -45,15 +45,6 @@ std::string EscapeString(const Slice& value) {
return r;
}
-bool ConsumeChar(Slice* in, char c) {
- if (!in->empty() && (*in)[0] == c) {
- in->remove_prefix(1);
- return true;
- } else {
- return false;
- }
-}
-
bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
uint64_t v = 0;
int digits = 0;
diff --git a/src/leveldb/util/logging.h b/src/leveldb/util/logging.h
index b0c5da813e..1b450d2480 100644
--- a/src/leveldb/util/logging.h
+++ b/src/leveldb/util/logging.h
@@ -32,10 +32,6 @@ extern std::string NumberToString(uint64_t num);
// Escapes any non-printable characters found in "value".
extern std::string EscapeString(const Slice& value);
-// If *in starts with "c", advances *in past the first character and
-// returns true. Otherwise, returns false.
-extern bool ConsumeChar(Slice* in, char c);
-
// Parse a human-readable number from "*in" into *value. On success,
// advances "*in" past the consumed number and sets "*val" to the
// numeric value. Otherwise, returns false and leaves *in in an
diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h
index da5ba61c7b..d997d56e00 100644
--- a/src/leveldbwrapper.h
+++ b/src/leveldbwrapper.h
@@ -6,6 +6,7 @@
#define BITCOIN_LEVELDBWRAPPER_H
#include "serialize.h"
+#include "streams.h"
#include "util.h"
#include "version.h"
diff --git a/src/main.cpp b/src/main.cpp
index 0cfe90beda..008a059103 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -633,10 +633,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
reason = "scriptsig-not-pushonly";
return false;
}
- if (!txin.scriptSig.HasCanonicalPushes()) {
- reason = "scriptsig-non-canonical-push";
- return false;
- }
}
unsigned int nDataOut = 0;
diff --git a/src/main.h b/src/main.h
index 1ef51918c5..1941ca7059 100644
--- a/src/main.h
+++ b/src/main.h
@@ -10,10 +10,12 @@
#include "config/bitcoin-config.h"
#endif
+#include "amount.h"
#include "chain.h"
#include "chainparams.h"
#include "coins.h"
-#include "core.h"
+#include "core/block.h"
+#include "core/transaction.h"
#include "net.h"
#include "pow.h"
#include "script/script.h"
@@ -23,6 +25,7 @@
#include "tinyformat.h"
#include "txmempool.h"
#include "uint256.h"
+#include "undo.h"
#include <algorithm>
#include <exception>
@@ -127,7 +130,6 @@ static const uint64_t nMinDiskSpace = 52428800;
class CBlockTreeDB;
-class CTxUndo;
class CScriptCheck;
class CValidationState;
class CValidationInterface;
diff --git a/src/miner.cpp b/src/miner.cpp
index eefccfd641..0235de3ab3 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -5,7 +5,9 @@
#include "miner.h"
-#include "core.h"
+#include "amount.h"
+#include "core/block.h"
+#include "core/transaction.h"
#include "hash.h"
#include "main.h"
#include "net.h"
diff --git a/src/net.cpp b/src/net.cpp
index 6cf64f51c3..6cccdca952 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -11,7 +11,7 @@
#include "addrman.h"
#include "chainparams.h"
-#include "core.h"
+#include "core/transaction.h"
#include "ui_interface.h"
#ifdef WIN32
diff --git a/src/net.h b/src/net.h
index 18da24183f..340158512d 100644
--- a/src/net.h
+++ b/src/net.h
@@ -14,6 +14,7 @@
#include "netbase.h"
#include "protocol.h"
#include "random.h"
+#include "streams.h"
#include "sync.h"
#include "uint256.h"
#include "utilstrencodings.h"
diff --git a/src/pow.cpp b/src/pow.cpp
index 75fbfc6a6d..af7fc488ef 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -6,7 +6,7 @@
#include "pow.h"
#include "chainparams.h"
-#include "core.h"
+#include "core/block.h"
#include "main.h"
#include "timedata.h"
#include "uint256.h"
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 423b559bf7..c85f569fd3 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -4,7 +4,7 @@
#include "bitcoinunits.h"
-#include "core.h"
+#include "core/transaction.h"
#include <QStringList>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 91bb10755a..22a1f019e9 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -9,7 +9,7 @@
#include "qvalidatedlineedit.h"
#include "walletmodel.h"
-#include "core.h"
+#include "core/transaction.h"
#include "init.h"
#include "main.h"
#include "protocol.h"
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 6db654dff7..c941ebd4ca 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -11,6 +11,7 @@
#include "bitcoinunits.h"
#include "guiutil.h"
+#include "amount.h"
#include "init.h"
#include "main.h"
#include "net.h"
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 0e5802922c..5deac8007c 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -7,6 +7,7 @@
#include "bitcoinunits.h"
#include "guiutil.h"
#include "optionsmodel.h"
+#include "streams.h"
#include <boost/foreach.hpp>
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 5beac0512a..78f5569895 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -225,7 +225,7 @@ Value getblockhash(const Array& params, bool fHelp)
int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
- throw runtime_error("Block number out of range.");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
CBlockIndex* pblockindex = chainActive[nHeight];
return pblockindex->GetBlockHash().GetHex();
@@ -319,6 +319,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
Object ret;
CCoinsStats stats;
+ pcoinsTip->Flush();
if (pcoinsTip->GetStats(stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index c767835a27..8af3c46348 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "amount.h"
#include "chainparams.h"
#include "core_io.h"
#include "init.h"
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index fdfcb59eeb..d3ce3b3191 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
-#include "core.h"
+#include "core/transaction.h"
#include "core_io.h"
#include "init.h"
#include "keystore.h"
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 68bb4068b8..2728fb4fb3 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "amount.h"
#include "base58.h"
#include "core_io.h"
#include "rpcserver.h"
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index cd73b88210..3625972ebf 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -5,7 +5,7 @@
#include "interpreter.h"
-#include "core.h"
+#include "core/transaction.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha2.h"
@@ -157,6 +157,29 @@ bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) {
return true;
}
+bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
+ if (data.size() == 0) {
+ // Could have used OP_0.
+ return opcode == OP_0;
+ } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) {
+ // Could have used OP_1 .. OP_16.
+ return opcode == OP_1 + (data[0] - 1);
+ } else if (data.size() == 1 && data[0] == 0x81) {
+ // Could have used OP_1NEGATE.
+ return opcode == OP_1NEGATE;
+ } else if (data.size() <= 75) {
+ // Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
+ return opcode == data.size();
+ } else if (data.size() <= 255) {
+ // Could have used OP_PUSHDATA.
+ return opcode == OP_PUSHDATA1;
+ } else if (data.size() <= 65535) {
+ // Could have used OP_PUSHDATA2.
+ return opcode == OP_PUSHDATA2;
+ }
+ return true;
+}
+
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker)
{
CScript::const_iterator pc = script.begin();
@@ -169,6 +192,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (script.size() > 10000)
return false;
int nOpCount = 0;
+ bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
try
{
@@ -205,9 +229,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
opcode == OP_RSHIFT)
return false; // Disabled opcodes.
- if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4)
+ if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
+ if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
+ return false;
+ }
stack.push_back(vchPushValue);
- else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
+ } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode)
{
//
@@ -234,6 +261,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// ( -- value)
CScriptNum bn((int)opcode - (int)(OP_1 - 1));
stack.push_back(bn.getvch());
+ // The result of these opcodes should always be the minimal way to push the data
+ // they push, so no need for a CheckMinimalPush here.
}
break;
@@ -458,7 +487,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
if (stack.size() < 2)
return false;
- int n = CScriptNum(stacktop(-1)).getint();
+ int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
popstack(stack);
if (n < 0 || n >= (int)stack.size())
return false;
@@ -557,7 +586,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (in -- out)
if (stack.size() < 1)
return false;
- CScriptNum bn(stacktop(-1));
+ CScriptNum bn(stacktop(-1), fRequireMinimal);
switch (opcode)
{
case OP_1ADD: bn += bnOne; break;
@@ -590,8 +619,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (x1 x2 -- out)
if (stack.size() < 2)
return false;
- CScriptNum bn1(stacktop(-2));
- CScriptNum bn2(stacktop(-1));
+ CScriptNum bn1(stacktop(-2), fRequireMinimal);
+ CScriptNum bn2(stacktop(-1), fRequireMinimal);
CScriptNum bn(0);
switch (opcode)
{
@@ -635,9 +664,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (x min max -- out)
if (stack.size() < 3)
return false;
- CScriptNum bn1(stacktop(-3));
- CScriptNum bn2(stacktop(-2));
- CScriptNum bn3(stacktop(-1));
+ CScriptNum bn1(stacktop(-3), fRequireMinimal);
+ CScriptNum bn2(stacktop(-2), fRequireMinimal);
+ CScriptNum bn3(stacktop(-1), fRequireMinimal);
bool fValue = (bn2 <= bn1 && bn1 < bn3);
popstack(stack);
popstack(stack);
@@ -727,7 +756,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ((int)stack.size() < i)
return false;
- int nKeysCount = CScriptNum(stacktop(-i)).getint();
+ int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
if (nKeysCount < 0 || nKeysCount > 20)
return false;
nOpCount += nKeysCount;
@@ -738,7 +767,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if ((int)stack.size() < i)
return false;
- int nSigsCount = CScriptNum(stacktop(-i)).getint();
+ int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
if (nSigsCount < 0 || nSigsCount > nKeysCount)
return false;
int isig = ++i;
@@ -980,6 +1009,10 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker)
{
+ if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
+ return false;
+ }
+
vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker))
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index de5ce2ced1..5133c80aab 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -46,6 +46,16 @@ enum
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
+
+ // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
+ SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
+
+ // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
+ // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
+ // any other push causes the script to fail (BIP62 rule 3).
+ // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
+ // (softfork safe)
+ SCRIPT_VERIFY_MINIMALDATA = (1U << 6)
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 3e19d0c2bf..b879d72d6b 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -12,7 +12,7 @@ namespace {
inline std::string ValueString(const std::vector<unsigned char>& vch)
{
if (vch.size() <= 4)
- return strprintf("%d", CScriptNum(vch).getint());
+ return strprintf("%d", CScriptNum(vch, false).getint());
else
return HexStr(vch);
}
@@ -230,7 +230,7 @@ bool CScript::IsPushOnly() const
return false;
// Note that IsPushOnly() *does* consider OP_RESERVED to be a
// push-type opcode, however execution of OP_RESERVED fails, so
- // it's not relevant to P2SH as the scriptSig would fail prior to
+ // it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
// the P2SH special validation code being executed.
if (opcode > OP_16)
return false;
@@ -238,33 +238,6 @@ bool CScript::IsPushOnly() const
return true;
}
-bool CScript::HasCanonicalPushes() const
-{
- const_iterator pc = begin();
- while (pc < end())
- {
- opcodetype opcode;
- std::vector<unsigned char> data;
- if (!GetOp(pc, opcode, data))
- return false;
- if (opcode > OP_16)
- continue;
- if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
- // Could have used an OP_n code, rather than a 1-byte push.
- return false;
- if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
- // Could have used a normal n-byte push, rather than OP_PUSHDATA1.
- return false;
- if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
- // Could have used an OP_PUSHDATA1.
- return false;
- if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
- // Could have used an OP_PUSHDATA2.
- return false;
- }
- return true;
-}
-
std::string CScript::ToString() const
{
std::string str;
diff --git a/src/script/script.h b/src/script/script.h
index d450db5cad..05f2e7e3a9 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -192,10 +192,29 @@ public:
m_value = n;
}
- explicit CScriptNum(const std::vector<unsigned char>& vch)
+ explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal)
{
- if (vch.size() > nMaxNumSize)
- throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow");
+ if (vch.size() > nMaxNumSize) {
+ throw scriptnum_error("script number overflow");
+ }
+ if (fRequireMinimal && vch.size() > 0) {
+ // Check that the number is encoded with the minimum possible
+ // number of bytes.
+ //
+ // If the most-significant-byte - excluding the sign bit - is zero
+ // then we're not minimal. Note how this test also rejects the
+ // negative-zero encoding, 0x80.
+ if ((vch.back() & 0x7f) == 0) {
+ // One exception: if there's more than one byte and the most
+ // significant bit of the second-most-significant-byte is set
+ // it would conflict with the sign bit. An example of this case
+ // is +-255, which encode to 0xff00 and 0xff80 respectively.
+ // (big-endian).
+ if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
+ throw scriptnum_error("non-minimally encoded script number");
+ }
+ }
+ }
m_value = set_vch(vch);
}
@@ -319,7 +338,6 @@ private:
int64_t m_value;
};
-
/** Serialized script, used inside transaction inputs and outputs */
class CScript : public std::vector<unsigned char>
{
@@ -330,6 +348,10 @@ protected:
{
push_back(n + (OP_1 - 1));
}
+ else if (n == 0)
+ {
+ push_back(OP_0);
+ }
else
{
*this << CScriptNum::serialize(n);
@@ -551,12 +573,9 @@ public:
bool IsPayToScriptHash() const;
- // Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical).
+ // Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
bool IsPushOnly() const;
- // Called by IsStandardTx.
- bool HasCanonicalPushes() const;
-
// Returns whether the script is guaranteed to fail at execution,
// regardless of the initial stack. This allows outputs to be pruned
// instantly when entering the UTXO set.
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index bf98c40394..0eab0626e5 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -5,7 +5,7 @@
#include "script/sign.h"
-#include "core.h"
+#include "core/transaction.h"
#include "key.h"
#include "keystore.h"
#include "script/standard.h"
diff --git a/src/script/standard.h b/src/script/standard.h
index 961b214c89..248b941a64 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -41,6 +41,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
// blocks and we must accept those blocks.
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
SCRIPT_VERIFY_STRICTENC |
+ SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_NULLDUMMY;
// For convenience, standard but not mandatory verify flags.
diff --git a/src/serialize.h b/src/serialize.h
index b9d5f95463..877ef8640a 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -6,8 +6,6 @@
#ifndef BITCOIN_SERIALIZE_H
#define BITCOIN_SERIALIZE_H
-#include "allocators.h"
-
#include <algorithm>
#include <assert.h>
#include <ios>
@@ -20,8 +18,6 @@
#include <utility>
#include <vector>
-class CAutoFile;
-class CDataStream;
class CScript;
static const unsigned int MAX_SIZE = 0x02000000;
@@ -761,8 +757,6 @@ inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionU
-typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
-
class CSizeComputer
{
protected:
@@ -792,551 +786,4 @@ public:
}
};
-/** Double ended buffer combining vector and stream-like interfaces.
- *
- * >> and << read and write unformatted data using the above serialization templates.
- * Fills with data in linear time; some stringstream implementations take N^2 time.
- */
-class CDataStream
-{
-protected:
- typedef CSerializeData vector_type;
- vector_type vch;
- unsigned int nReadPos;
-public:
- int nType;
- int nVersion;
-
- typedef vector_type::allocator_type allocator_type;
- typedef vector_type::size_type size_type;
- typedef vector_type::difference_type difference_type;
- typedef vector_type::reference reference;
- typedef vector_type::const_reference const_reference;
- typedef vector_type::value_type value_type;
- typedef vector_type::iterator iterator;
- typedef vector_type::const_iterator const_iterator;
- typedef vector_type::reverse_iterator reverse_iterator;
-
- explicit CDataStream(int nTypeIn, int nVersionIn)
- {
- Init(nTypeIn, nVersionIn);
- }
-
- CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
- {
- Init(nTypeIn, nVersionIn);
- }
-
-#if !defined(_MSC_VER) || _MSC_VER >= 1300
- CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
- {
- Init(nTypeIn, nVersionIn);
- }
-#endif
-
- CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
- {
- Init(nTypeIn, nVersionIn);
- }
-
- CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
- {
- Init(nTypeIn, nVersionIn);
- }
-
- CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
- {
- Init(nTypeIn, nVersionIn);
- }
-
- void Init(int nTypeIn, int nVersionIn)
- {
- nReadPos = 0;
- nType = nTypeIn;
- nVersion = nVersionIn;
- }
-
- CDataStream& operator+=(const CDataStream& b)
- {
- vch.insert(vch.end(), b.begin(), b.end());
- return *this;
- }
-
- friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
- {
- CDataStream ret = a;
- ret += b;
- return (ret);
- }
-
- std::string str() const
- {
- return (std::string(begin(), end()));
- }
-
-
- //
- // Vector subset
- //
- const_iterator begin() const { return vch.begin() + nReadPos; }
- iterator begin() { return vch.begin() + nReadPos; }
- const_iterator end() const { return vch.end(); }
- iterator end() { return vch.end(); }
- size_type size() const { return vch.size() - nReadPos; }
- bool empty() const { return vch.size() == nReadPos; }
- void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
- void reserve(size_type n) { vch.reserve(n + nReadPos); }
- const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
- reference operator[](size_type pos) { return vch[pos + nReadPos]; }
- void clear() { vch.clear(); nReadPos = 0; }
- iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
- void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
-
- void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
- {
- assert(last - first >= 0);
- if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
- {
- // special case for inserting at the front when there's room
- nReadPos -= (last - first);
- memcpy(&vch[nReadPos], &first[0], last - first);
- }
- else
- vch.insert(it, first, last);
- }
-
-#if !defined(_MSC_VER) || _MSC_VER >= 1300
- void insert(iterator it, const char* first, const char* last)
- {
- assert(last - first >= 0);
- if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
- {
- // special case for inserting at the front when there's room
- nReadPos -= (last - first);
- memcpy(&vch[nReadPos], &first[0], last - first);
- }
- else
- vch.insert(it, first, last);
- }
-#endif
-
- iterator erase(iterator it)
- {
- if (it == vch.begin() + nReadPos)
- {
- // special case for erasing from the front
- if (++nReadPos >= vch.size())
- {
- // whenever we reach the end, we take the opportunity to clear the buffer
- nReadPos = 0;
- return vch.erase(vch.begin(), vch.end());
- }
- return vch.begin() + nReadPos;
- }
- else
- return vch.erase(it);
- }
-
- iterator erase(iterator first, iterator last)
- {
- if (first == vch.begin() + nReadPos)
- {
- // special case for erasing from the front
- if (last == vch.end())
- {
- nReadPos = 0;
- return vch.erase(vch.begin(), vch.end());
- }
- else
- {
- nReadPos = (last - vch.begin());
- return last;
- }
- }
- else
- return vch.erase(first, last);
- }
-
- inline void Compact()
- {
- vch.erase(vch.begin(), vch.begin() + nReadPos);
- nReadPos = 0;
- }
-
- bool Rewind(size_type n)
- {
- // Rewind by n characters if the buffer hasn't been compacted yet
- if (n > nReadPos)
- return false;
- nReadPos -= n;
- return true;
- }
-
-
- //
- // Stream subset
- //
- bool eof() const { return size() == 0; }
- CDataStream* rdbuf() { return this; }
- int in_avail() { return size(); }
-
- void SetType(int n) { nType = n; }
- int GetType() { return nType; }
- void SetVersion(int n) { nVersion = n; }
- int GetVersion() { return nVersion; }
- void ReadVersion() { *this >> nVersion; }
- void WriteVersion() { *this << nVersion; }
-
- CDataStream& read(char* pch, size_t nSize)
- {
- // Read from the beginning of the buffer
- unsigned int nReadPosNext = nReadPos + nSize;
- if (nReadPosNext >= vch.size())
- {
- if (nReadPosNext > vch.size())
- {
- throw std::ios_base::failure("CDataStream::read() : end of data");
- }
- memcpy(pch, &vch[nReadPos], nSize);
- nReadPos = 0;
- vch.clear();
- return (*this);
- }
- memcpy(pch, &vch[nReadPos], nSize);
- nReadPos = nReadPosNext;
- return (*this);
- }
-
- CDataStream& ignore(int nSize)
- {
- // Ignore from the beginning of the buffer
- assert(nSize >= 0);
- unsigned int nReadPosNext = nReadPos + nSize;
- if (nReadPosNext >= vch.size())
- {
- if (nReadPosNext > vch.size())
- throw std::ios_base::failure("CDataStream::ignore() : end of data");
- nReadPos = 0;
- vch.clear();
- return (*this);
- }
- nReadPos = nReadPosNext;
- return (*this);
- }
-
- CDataStream& write(const char* pch, size_t nSize)
- {
- // Write to the end of the buffer
- vch.insert(vch.end(), pch, pch + nSize);
- return (*this);
- }
-
- template<typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
- {
- // Special case: stream << stream concatenates like stream += stream
- if (!vch.empty())
- s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
- }
-
- template<typename T>
- unsigned int GetSerializeSize(const T& obj)
- {
- // Tells the size of the object if serialized to this stream
- return ::GetSerializeSize(obj, nType, nVersion);
- }
-
- template<typename T>
- CDataStream& operator<<(const T& obj)
- {
- // Serialize to this stream
- ::Serialize(*this, obj, nType, nVersion);
- return (*this);
- }
-
- template<typename T>
- CDataStream& operator>>(T& obj)
- {
- // Unserialize from this stream
- ::Unserialize(*this, obj, nType, nVersion);
- return (*this);
- }
-
- void GetAndClear(CSerializeData &data) {
- data.insert(data.end(), begin(), end());
- clear();
- }
-};
-
-
-
-
-
-
-
-
-
-
-/** Non-refcounted RAII wrapper for FILE*
- *
- * Will automatically close the file when it goes out of scope if not null.
- * If you're returning the file pointer, return file.release().
- * If you need to close the file early, use file.fclose() instead of fclose(file).
- */
-class CAutoFile
-{
-private:
- // Disallow copies
- CAutoFile(const CAutoFile&);
- CAutoFile& operator=(const CAutoFile&);
-
- int nType;
- int nVersion;
-
- FILE* file;
-
-public:
- CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn)
- {
- file = filenew;
- nType = nTypeIn;
- nVersion = nVersionIn;
- }
-
- ~CAutoFile()
- {
- fclose();
- }
-
- void fclose()
- {
- if (file) {
- ::fclose(file);
- file = NULL;
- }
- }
-
- /** Get wrapped FILE* with transfer of ownership.
- * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
- * of this function to clean up the returned FILE*.
- */
- FILE* release() { FILE* ret = file; file = NULL; return ret; }
-
- /** Get wrapped FILE* without transfer of ownership.
- * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
- * CAutoFile outlives use of the passed pointer.
- */
- FILE* Get() const { return file; }
-
- /** Return true if the wrapped FILE* is NULL, false otherwise.
- */
- bool IsNull() const { return (file == NULL); }
-
- //
- // Stream subset
- //
- void SetType(int n) { nType = n; }
- int GetType() { return nType; }
- void SetVersion(int n) { nVersion = n; }
- int GetVersion() { return nVersion; }
- void ReadVersion() { *this >> nVersion; }
- void WriteVersion() { *this << nVersion; }
-
- CAutoFile& read(char* pch, size_t nSize)
- {
- if (!file)
- throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
- if (fread(pch, 1, nSize, file) != nSize)
- throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
- return (*this);
- }
-
- CAutoFile& write(const char* pch, size_t nSize)
- {
- if (!file)
- throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
- if (fwrite(pch, 1, nSize, file) != nSize)
- throw std::ios_base::failure("CAutoFile::write : write failed");
- return (*this);
- }
-
- template<typename T>
- unsigned int GetSerializeSize(const T& obj)
- {
- // Tells the size of the object if serialized to this stream
- return ::GetSerializeSize(obj, nType, nVersion);
- }
-
- template<typename T>
- CAutoFile& operator<<(const T& obj)
- {
- // Serialize to this stream
- if (!file)
- throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
- ::Serialize(*this, obj, nType, nVersion);
- return (*this);
- }
-
- template<typename T>
- CAutoFile& operator>>(T& obj)
- {
- // Unserialize from this stream
- if (!file)
- throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
- ::Unserialize(*this, obj, nType, nVersion);
- return (*this);
- }
-};
-
-/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
- * deserialize from. It guarantees the ability to rewind a given number of bytes.
- *
- * Will automatically close the file when it goes out of scope if not null.
- * If you need to close the file early, use file.fclose() instead of fclose(file).
- */
-class CBufferedFile
-{
-private:
- // Disallow copies
- CBufferedFile(const CBufferedFile&);
- CBufferedFile& operator=(const CBufferedFile&);
-
- int nType;
- int nVersion;
-
- FILE *src; // source file
- uint64_t nSrcPos; // how many bytes have been read from source
- uint64_t nReadPos; // how many bytes have been read from this
- uint64_t nReadLimit; // up to which position we're allowed to read
- uint64_t nRewind; // how many bytes we guarantee to rewind
- std::vector<char> vchBuf; // the buffer
-
-protected:
- // read data from the source to fill the buffer
- bool Fill() {
- unsigned int pos = nSrcPos % vchBuf.size();
- unsigned int readNow = vchBuf.size() - pos;
- unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
- if (nAvail < readNow)
- readNow = nAvail;
- if (readNow == 0)
- return false;
- size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
- if (read == 0) {
- throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed");
- } else {
- nSrcPos += read;
- return true;
- }
- }
-
-public:
- CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
- nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
- {
- src = fileIn;
- nType = nTypeIn;
- nVersion = nVersionIn;
- }
-
- ~CBufferedFile()
- {
- fclose();
- }
-
- void fclose()
- {
- if (src) {
- ::fclose(src);
- src = NULL;
- }
- }
-
- // check whether we're at the end of the source file
- bool eof() const {
- return nReadPos == nSrcPos && feof(src);
- }
-
- // read a number of bytes
- CBufferedFile& read(char *pch, size_t nSize) {
- if (nSize + nReadPos > nReadLimit)
- throw std::ios_base::failure("Read attempted past buffer limit");
- if (nSize + nRewind > vchBuf.size())
- throw std::ios_base::failure("Read larger than buffer size");
- while (nSize > 0) {
- if (nReadPos == nSrcPos)
- Fill();
- unsigned int pos = nReadPos % vchBuf.size();
- size_t nNow = nSize;
- if (nNow + pos > vchBuf.size())
- nNow = vchBuf.size() - pos;
- if (nNow + nReadPos > nSrcPos)
- nNow = nSrcPos - nReadPos;
- memcpy(pch, &vchBuf[pos], nNow);
- nReadPos += nNow;
- pch += nNow;
- nSize -= nNow;
- }
- return (*this);
- }
-
- // return the current reading position
- uint64_t GetPos() {
- return nReadPos;
- }
-
- // rewind to a given reading position
- bool SetPos(uint64_t nPos) {
- nReadPos = nPos;
- if (nReadPos + nRewind < nSrcPos) {
- nReadPos = nSrcPos - nRewind;
- return false;
- } else if (nReadPos > nSrcPos) {
- nReadPos = nSrcPos;
- return false;
- } else {
- return true;
- }
- }
-
- bool Seek(uint64_t nPos) {
- long nLongPos = nPos;
- if (nPos != (uint64_t)nLongPos)
- return false;
- if (fseek(src, nLongPos, SEEK_SET))
- return false;
- nLongPos = ftell(src);
- nSrcPos = nLongPos;
- nReadPos = nLongPos;
- return true;
- }
-
- // prevent reading beyond a certain position
- // no argument removes the limit
- bool SetLimit(uint64_t nPos = (uint64_t)(-1)) {
- if (nPos < nReadPos)
- return false;
- nReadLimit = nPos;
- return true;
- }
-
- template<typename T>
- CBufferedFile& operator>>(T& obj) {
- // Unserialize from this stream
- ::Unserialize(*this, obj, nType, nVersion);
- return (*this);
- }
-
- // search for a given byte in the stream, and remain positioned on it
- void FindByte(char ch) {
- while (true) {
- if (nReadPos == nSrcPos)
- Fill();
- if (vchBuf[nReadPos % vchBuf.size()] == ch)
- break;
- nReadPos++;
- }
- }
-};
-
#endif // BITCOIN_SERIALIZE_H
diff --git a/src/streams.h b/src/streams.h
new file mode 100644
index 0000000000..b07b11eb3d
--- /dev/null
+++ b/src/streams.h
@@ -0,0 +1,571 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_STREAMS_H
+#define BITCOIN_STREAMS_H
+
+#include "allocators.h"
+#include "serialize.h"
+
+#include <algorithm>
+#include <assert.h>
+#include <ios>
+#include <limits>
+#include <map>
+#include <set>
+#include <stdint.h>
+#include <string>
+#include <string.h>
+#include <utility>
+#include <vector>
+
+/** Double ended buffer combining vector and stream-like interfaces.
+ *
+ * >> and << read and write unformatted data using the above serialization templates.
+ * Fills with data in linear time; some stringstream implementations take N^2 time.
+ */
+class CDataStream
+{
+protected:
+ typedef CSerializeData vector_type;
+ vector_type vch;
+ unsigned int nReadPos;
+public:
+ int nType;
+ int nVersion;
+
+ typedef vector_type::allocator_type allocator_type;
+ typedef vector_type::size_type size_type;
+ typedef vector_type::difference_type difference_type;
+ typedef vector_type::reference reference;
+ typedef vector_type::const_reference const_reference;
+ typedef vector_type::value_type value_type;
+ typedef vector_type::iterator iterator;
+ typedef vector_type::const_iterator const_iterator;
+ typedef vector_type::reverse_iterator reverse_iterator;
+
+ explicit CDataStream(int nTypeIn, int nVersionIn)
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1300
+ CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+#endif
+
+ CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ void Init(int nTypeIn, int nVersionIn)
+ {
+ nReadPos = 0;
+ nType = nTypeIn;
+ nVersion = nVersionIn;
+ }
+
+ CDataStream& operator+=(const CDataStream& b)
+ {
+ vch.insert(vch.end(), b.begin(), b.end());
+ return *this;
+ }
+
+ friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
+ {
+ CDataStream ret = a;
+ ret += b;
+ return (ret);
+ }
+
+ std::string str() const
+ {
+ return (std::string(begin(), end()));
+ }
+
+
+ //
+ // Vector subset
+ //
+ const_iterator begin() const { return vch.begin() + nReadPos; }
+ iterator begin() { return vch.begin() + nReadPos; }
+ const_iterator end() const { return vch.end(); }
+ iterator end() { return vch.end(); }
+ size_type size() const { return vch.size() - nReadPos; }
+ bool empty() const { return vch.size() == nReadPos; }
+ void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
+ void reserve(size_type n) { vch.reserve(n + nReadPos); }
+ const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
+ reference operator[](size_type pos) { return vch[pos + nReadPos]; }
+ void clear() { vch.clear(); nReadPos = 0; }
+ iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
+ void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
+
+ void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
+ {
+ assert(last - first >= 0);
+ if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
+ {
+ // special case for inserting at the front when there's room
+ nReadPos -= (last - first);
+ memcpy(&vch[nReadPos], &first[0], last - first);
+ }
+ else
+ vch.insert(it, first, last);
+ }
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1300
+ void insert(iterator it, const char* first, const char* last)
+ {
+ assert(last - first >= 0);
+ if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
+ {
+ // special case for inserting at the front when there's room
+ nReadPos -= (last - first);
+ memcpy(&vch[nReadPos], &first[0], last - first);
+ }
+ else
+ vch.insert(it, first, last);
+ }
+#endif
+
+ iterator erase(iterator it)
+ {
+ if (it == vch.begin() + nReadPos)
+ {
+ // special case for erasing from the front
+ if (++nReadPos >= vch.size())
+ {
+ // whenever we reach the end, we take the opportunity to clear the buffer
+ nReadPos = 0;
+ return vch.erase(vch.begin(), vch.end());
+ }
+ return vch.begin() + nReadPos;
+ }
+ else
+ return vch.erase(it);
+ }
+
+ iterator erase(iterator first, iterator last)
+ {
+ if (first == vch.begin() + nReadPos)
+ {
+ // special case for erasing from the front
+ if (last == vch.end())
+ {
+ nReadPos = 0;
+ return vch.erase(vch.begin(), vch.end());
+ }
+ else
+ {
+ nReadPos = (last - vch.begin());
+ return last;
+ }
+ }
+ else
+ return vch.erase(first, last);
+ }
+
+ inline void Compact()
+ {
+ vch.erase(vch.begin(), vch.begin() + nReadPos);
+ nReadPos = 0;
+ }
+
+ bool Rewind(size_type n)
+ {
+ // Rewind by n characters if the buffer hasn't been compacted yet
+ if (n > nReadPos)
+ return false;
+ nReadPos -= n;
+ return true;
+ }
+
+
+ //
+ // Stream subset
+ //
+ bool eof() const { return size() == 0; }
+ CDataStream* rdbuf() { return this; }
+ int in_avail() { return size(); }
+
+ void SetType(int n) { nType = n; }
+ int GetType() { return nType; }
+ void SetVersion(int n) { nVersion = n; }
+ int GetVersion() { return nVersion; }
+ void ReadVersion() { *this >> nVersion; }
+ void WriteVersion() { *this << nVersion; }
+
+ CDataStream& read(char* pch, size_t nSize)
+ {
+ // Read from the beginning of the buffer
+ unsigned int nReadPosNext = nReadPos + nSize;
+ if (nReadPosNext >= vch.size())
+ {
+ if (nReadPosNext > vch.size())
+ {
+ throw std::ios_base::failure("CDataStream::read() : end of data");
+ }
+ memcpy(pch, &vch[nReadPos], nSize);
+ nReadPos = 0;
+ vch.clear();
+ return (*this);
+ }
+ memcpy(pch, &vch[nReadPos], nSize);
+ nReadPos = nReadPosNext;
+ return (*this);
+ }
+
+ CDataStream& ignore(int nSize)
+ {
+ // Ignore from the beginning of the buffer
+ assert(nSize >= 0);
+ unsigned int nReadPosNext = nReadPos + nSize;
+ if (nReadPosNext >= vch.size())
+ {
+ if (nReadPosNext > vch.size())
+ throw std::ios_base::failure("CDataStream::ignore() : end of data");
+ nReadPos = 0;
+ vch.clear();
+ return (*this);
+ }
+ nReadPos = nReadPosNext;
+ return (*this);
+ }
+
+ CDataStream& write(const char* pch, size_t nSize)
+ {
+ // Write to the end of the buffer
+ vch.insert(vch.end(), pch, pch + nSize);
+ return (*this);
+ }
+
+ template<typename Stream>
+ void Serialize(Stream& s, int nType, int nVersion) const
+ {
+ // Special case: stream << stream concatenates like stream += stream
+ if (!vch.empty())
+ s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
+ }
+
+ template<typename T>
+ unsigned int GetSerializeSize(const T& obj)
+ {
+ // Tells the size of the object if serialized to this stream
+ return ::GetSerializeSize(obj, nType, nVersion);
+ }
+
+ template<typename T>
+ CDataStream& operator<<(const T& obj)
+ {
+ // Serialize to this stream
+ ::Serialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ template<typename T>
+ CDataStream& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ void GetAndClear(CSerializeData &data) {
+ data.insert(data.end(), begin(), end());
+ clear();
+ }
+};
+
+
+
+
+
+
+
+
+
+
+/** Non-refcounted RAII wrapper for FILE*
+ *
+ * Will automatically close the file when it goes out of scope if not null.
+ * If you're returning the file pointer, return file.release().
+ * If you need to close the file early, use file.fclose() instead of fclose(file).
+ */
+class CAutoFile
+{
+private:
+ // Disallow copies
+ CAutoFile(const CAutoFile&);
+ CAutoFile& operator=(const CAutoFile&);
+
+ int nType;
+ int nVersion;
+
+ FILE* file;
+
+public:
+ CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn)
+ {
+ file = filenew;
+ nType = nTypeIn;
+ nVersion = nVersionIn;
+ }
+
+ ~CAutoFile()
+ {
+ fclose();
+ }
+
+ void fclose()
+ {
+ if (file) {
+ ::fclose(file);
+ file = NULL;
+ }
+ }
+
+ /** Get wrapped FILE* with transfer of ownership.
+ * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
+ * of this function to clean up the returned FILE*.
+ */
+ FILE* release() { FILE* ret = file; file = NULL; return ret; }
+
+ /** Get wrapped FILE* without transfer of ownership.
+ * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
+ * CAutoFile outlives use of the passed pointer.
+ */
+ FILE* Get() const { return file; }
+
+ /** Return true if the wrapped FILE* is NULL, false otherwise.
+ */
+ bool IsNull() const { return (file == NULL); }
+
+ //
+ // Stream subset
+ //
+ void SetType(int n) { nType = n; }
+ int GetType() { return nType; }
+ void SetVersion(int n) { nVersion = n; }
+ int GetVersion() { return nVersion; }
+ void ReadVersion() { *this >> nVersion; }
+ void WriteVersion() { *this << nVersion; }
+
+ CAutoFile& read(char* pch, size_t nSize)
+ {
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
+ if (fread(pch, 1, nSize, file) != nSize)
+ throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
+ return (*this);
+ }
+
+ CAutoFile& write(const char* pch, size_t nSize)
+ {
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
+ if (fwrite(pch, 1, nSize, file) != nSize)
+ throw std::ios_base::failure("CAutoFile::write : write failed");
+ return (*this);
+ }
+
+ template<typename T>
+ unsigned int GetSerializeSize(const T& obj)
+ {
+ // Tells the size of the object if serialized to this stream
+ return ::GetSerializeSize(obj, nType, nVersion);
+ }
+
+ template<typename T>
+ CAutoFile& operator<<(const T& obj)
+ {
+ // Serialize to this stream
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
+ ::Serialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ template<typename T>
+ CAutoFile& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
+ ::Unserialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+};
+
+/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
+ * deserialize from. It guarantees the ability to rewind a given number of bytes.
+ *
+ * Will automatically close the file when it goes out of scope if not null.
+ * If you need to close the file early, use file.fclose() instead of fclose(file).
+ */
+class CBufferedFile
+{
+private:
+ // Disallow copies
+ CBufferedFile(const CBufferedFile&);
+ CBufferedFile& operator=(const CBufferedFile&);
+
+ int nType;
+ int nVersion;
+
+ FILE *src; // source file
+ uint64_t nSrcPos; // how many bytes have been read from source
+ uint64_t nReadPos; // how many bytes have been read from this
+ uint64_t nReadLimit; // up to which position we're allowed to read
+ uint64_t nRewind; // how many bytes we guarantee to rewind
+ std::vector<char> vchBuf; // the buffer
+
+protected:
+ // read data from the source to fill the buffer
+ bool Fill() {
+ unsigned int pos = nSrcPos % vchBuf.size();
+ unsigned int readNow = vchBuf.size() - pos;
+ unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
+ if (nAvail < readNow)
+ readNow = nAvail;
+ if (readNow == 0)
+ return false;
+ size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
+ if (read == 0) {
+ throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed");
+ } else {
+ nSrcPos += read;
+ return true;
+ }
+ }
+
+public:
+ CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
+ nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
+ {
+ src = fileIn;
+ nType = nTypeIn;
+ nVersion = nVersionIn;
+ }
+
+ ~CBufferedFile()
+ {
+ fclose();
+ }
+
+ void fclose()
+ {
+ if (src) {
+ ::fclose(src);
+ src = NULL;
+ }
+ }
+
+ // check whether we're at the end of the source file
+ bool eof() const {
+ return nReadPos == nSrcPos && feof(src);
+ }
+
+ // read a number of bytes
+ CBufferedFile& read(char *pch, size_t nSize) {
+ if (nSize + nReadPos > nReadLimit)
+ throw std::ios_base::failure("Read attempted past buffer limit");
+ if (nSize + nRewind > vchBuf.size())
+ throw std::ios_base::failure("Read larger than buffer size");
+ while (nSize > 0) {
+ if (nReadPos == nSrcPos)
+ Fill();
+ unsigned int pos = nReadPos % vchBuf.size();
+ size_t nNow = nSize;
+ if (nNow + pos > vchBuf.size())
+ nNow = vchBuf.size() - pos;
+ if (nNow + nReadPos > nSrcPos)
+ nNow = nSrcPos - nReadPos;
+ memcpy(pch, &vchBuf[pos], nNow);
+ nReadPos += nNow;
+ pch += nNow;
+ nSize -= nNow;
+ }
+ return (*this);
+ }
+
+ // return the current reading position
+ uint64_t GetPos() {
+ return nReadPos;
+ }
+
+ // rewind to a given reading position
+ bool SetPos(uint64_t nPos) {
+ nReadPos = nPos;
+ if (nReadPos + nRewind < nSrcPos) {
+ nReadPos = nSrcPos - nRewind;
+ return false;
+ } else if (nReadPos > nSrcPos) {
+ nReadPos = nSrcPos;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ bool Seek(uint64_t nPos) {
+ long nLongPos = nPos;
+ if (nPos != (uint64_t)nLongPos)
+ return false;
+ if (fseek(src, nLongPos, SEEK_SET))
+ return false;
+ nLongPos = ftell(src);
+ nSrcPos = nLongPos;
+ nReadPos = nLongPos;
+ return true;
+ }
+
+ // prevent reading beyond a certain position
+ // no argument removes the limit
+ bool SetLimit(uint64_t nPos = (uint64_t)(-1)) {
+ if (nPos < nReadPos)
+ return false;
+ nReadLimit = nPos;
+ return true;
+ }
+
+ template<typename T>
+ CBufferedFile& operator>>(T& obj) {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ // search for a given byte in the stream, and remain positioned on it
+ void FindByte(char ch) {
+ while (true) {
+ if (nReadPos == nSrcPos)
+ Fill();
+ if (vchBuf[nReadPos % vchBuf.size()] == ch)
+ break;
+ nReadPos++;
+ }
+ }
+};
+
+#endif // BITCOIN_STREAMS_H
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 4af87cf8ef..28610f0d2e 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -10,6 +10,7 @@
#include "data/alertTests.raw.h"
#include "serialize.h"
+#include "streams.h"
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index 719955ba85..bf404cf0cf 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
+#include "compressor.h"
#include "util.h"
#include <stdint.h>
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index b6447cb221..6f451a36ee 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -384,6 +384,101 @@ nSequences are max.
["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
+["MINIMALDATA enforcement for PUSHDATAs"],
+
+["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0"],
+["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"],
+["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"],
+["0x01 0x02", "DROP 1", "MINIMALDATA"],
+["0x01 0x03", "DROP 1", "MINIMALDATA"],
+["0x01 0x04", "DROP 1", "MINIMALDATA"],
+["0x01 0x05", "DROP 1", "MINIMALDATA"],
+["0x01 0x06", "DROP 1", "MINIMALDATA"],
+["0x01 0x07", "DROP 1", "MINIMALDATA"],
+["0x01 0x08", "DROP 1", "MINIMALDATA"],
+["0x01 0x09", "DROP 1", "MINIMALDATA"],
+["0x01 0x0a", "DROP 1", "MINIMALDATA"],
+["0x01 0x0b", "DROP 1", "MINIMALDATA"],
+["0x01 0x0c", "DROP 1", "MINIMALDATA"],
+["0x01 0x0d", "DROP 1", "MINIMALDATA"],
+["0x01 0x0e", "DROP 1", "MINIMALDATA"],
+["0x01 0x0f", "DROP 1", "MINIMALDATA"],
+["0x01 0x10", "DROP 1", "MINIMALDATA"],
+
+["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
+ "PUSHDATA1 of 72 bytes minimally represented by direct push"],
+
+["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
+ "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"],
+
+["0x4f 0x00100000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
+ "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"],
+
+
+["MINIMALDATA enforcement for numeric arguments"],
+
+["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
+["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"],
+["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
+["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5"],
+["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5"],
+["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5"],
+["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5"],
+["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff"],
+["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f"],
+["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff"],
+["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f"],
+
+["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"],
+
+["1 0x02 0x0000", "PICK DROP", "MINIMALDATA"],
+["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "ABS DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA"],
+
+["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA"],
+["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA"],
+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA"],
+
+["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA"],
+["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA"],
+
+["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
+
+
[
"0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
@@ -504,6 +599,24 @@ nSequences are max.
"NULLDUMMY",
"3-of-3 NOT with invalid sig with nonzero dummy"
],
+[
+ "0 0x47 0x3044022035341cc377b19138f944f90c45772cb06338c6d56a4c0c31a65bf1a8a105fadc022046dd232850b6bacb25879c9da82a7a628982aa19d055f1753468f68047662e0301 DUP",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+ "SIGPUSHONLY",
+ "2-of-2 with two identical keys and sigs pushed using OP_DUP"
+],
+[
+ "0x47 0x304402204d8b99eea2f53382fd67e0dbc8ed0596bd614aa0dad6bc6843c7860c79b901c3022062f022a71993013e3d9b22302a8e4b40109d7bb057aeb250b9aab2197b3e96b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+ "",
+ "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"
+],
+[
+ "0x47 0x30440220078c887c33abc67fbbd827ceb3f661c1c459e78218161b652f23e3ca76cfabbd022047df245eacb8a88d8c5ca7b5228e3b4d070c102d2f542433362d3f443cd24eda01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
+ "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+ "SIGPUSHONLY",
+ "P2SH(P2PK) with non-push scriptSig"
+],
["The End"]
]
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index 88bec7238c..439c82ef32 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -527,8 +527,139 @@ nSequences are max.
"P2SH,STRICTENC",
"Basic PUSHDATA1 signedness check"],
+["all PUSHDATA forms are equivalent"],
+
+["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA1 of 75 bytes equals direct push of it"],
+["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"],
+
["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
+["Numeric pushes"],
+
+["0x01 0x81", "0x4f EQUAL", "", "OP1_NEGATE pushes 0x81"],
+["0x01 0x01", "0x51 EQUAL", "", "OP_1 pushes 0x01"],
+["0x01 0x02", "0x52 EQUAL", "", "OP_2 pushes 0x02"],
+["0x01 0x03", "0x53 EQUAL", "", "OP_3 pushes 0x03"],
+["0x01 0x04", "0x54 EQUAL", "", "OP_4 pushes 0x04"],
+["0x01 0x05", "0x55 EQUAL", "", "OP_5 pushes 0x05"],
+["0x01 0x06", "0x56 EQUAL", "", "OP_6 pushes 0x06"],
+["0x01 0x07", "0x57 EQUAL", "", "OP_7 pushes 0x07"],
+["0x01 0x08", "0x58 EQUAL", "", "OP_8 pushes 0x08"],
+["0x01 0x09", "0x59 EQUAL", "", "OP_9 pushes 0x09"],
+["0x01 0x0a", "0x5a EQUAL", "", "OP_10 pushes 0x0a"],
+["0x01 0x0b", "0x5b EQUAL", "", "OP_11 pushes 0x0b"],
+["0x01 0x0c", "0x5c EQUAL", "", "OP_12 pushes 0x0c"],
+["0x01 0x0d", "0x5d EQUAL", "", "OP_13 pushes 0x0d"],
+["0x01 0x0e", "0x5e EQUAL", "", "OP_14 pushes 0x0e"],
+["0x01 0x0f", "0x5f EQUAL", "", "OP_15 pushes 0x0f"],
+["0x01 0x10", "0x60 EQUAL", "", "OP_16 pushes 0x10"],
+
+["Equivalency of different numeric encodings"],
+
+["0x02 0x8000", "128 NUMEQUAL", "", "0x8000 equals 128"],
+["0x01 0x00", "0 NUMEQUAL", "", "0x00 numequals 0"],
+["0x01 0x80", "0 NUMEQUAL", "", "0x80 (negative zero) numequals 0"],
+["0x02 0x0080", "0 NUMEQUAL", "", "0x0080 numequals 0"],
+["0x02 0x0500", "5 NUMEQUAL", "", "0x0500 numequals 5"],
+["0x03 0xff7f80", "0x02 0xffff NUMEQUAL", "", ""],
+["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", ""],
+["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", ""],
+["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", ""],
+
+["Unevaluated non-minimal pushes are ignored"],
+
+["0 IF 0x4c 0x00 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA1 ignored"],
+["0 IF 0x4d 0x0000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA2 ignored"],
+["0 IF 0x4c 0x00000000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA4 ignored"],
+["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "1NEGATE equiv"],
+["0 IF 0x01 0x01 ENDIF 1", "", "MINIMALDATA", "OP_1 equiv"],
+["0 IF 0x01 0x02 ENDIF 1", "", "MINIMALDATA", "OP_2 equiv"],
+["0 IF 0x01 0x03 ENDIF 1", "", "MINIMALDATA", "OP_3 equiv"],
+["0 IF 0x01 0x04 ENDIF 1", "", "MINIMALDATA", "OP_4 equiv"],
+["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "OP_5 equiv"],
+["0 IF 0x01 0x06 ENDIF 1", "", "MINIMALDATA", "OP_6 equiv"],
+["0 IF 0x01 0x07 ENDIF 1", "", "MINIMALDATA", "OP_7 equiv"],
+["0 IF 0x01 0x08 ENDIF 1", "", "MINIMALDATA", "OP_8 equiv"],
+["0 IF 0x01 0x09 ENDIF 1", "", "MINIMALDATA", "OP_9 equiv"],
+["0 IF 0x01 0x0a ENDIF 1", "", "MINIMALDATA", "OP_10 equiv"],
+["0 IF 0x01 0x0b ENDIF 1", "", "MINIMALDATA", "OP_11 equiv"],
+["0 IF 0x01 0x0c ENDIF 1", "", "MINIMALDATA", "OP_12 equiv"],
+["0 IF 0x01 0x0d ENDIF 1", "", "MINIMALDATA", "OP_13 equiv"],
+["0 IF 0x01 0x0e ENDIF 1", "", "MINIMALDATA", "OP_14 equiv"],
+["0 IF 0x01 0x0f ENDIF 1", "", "MINIMALDATA", "OP_15 equiv"],
+["0 IF 0x01 0x10 ENDIF 1", "", "MINIMALDATA", "OP_16 equiv"],
+
+["Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed"],
+
+["0x01 0x00", "1", "MINIMALDATA"],
+["0x01 0x80", "1", "MINIMALDATA"],
+["0x02 0x0180", "1", "MINIMALDATA"],
+["0x02 0x0100", "1", "MINIMALDATA"],
+["0x02 0x0200", "1", "MINIMALDATA"],
+["0x02 0x0300", "1", "MINIMALDATA"],
+["0x02 0x0400", "1", "MINIMALDATA"],
+["0x02 0x0500", "1", "MINIMALDATA"],
+["0x02 0x0600", "1", "MINIMALDATA"],
+["0x02 0x0700", "1", "MINIMALDATA"],
+["0x02 0x0800", "1", "MINIMALDATA"],
+["0x02 0x0900", "1", "MINIMALDATA"],
+["0x02 0x0a00", "1", "MINIMALDATA"],
+["0x02 0x0b00", "1", "MINIMALDATA"],
+["0x02 0x0c00", "1", "MINIMALDATA"],
+["0x02 0x0d00", "1", "MINIMALDATA"],
+["0x02 0x0e00", "1", "MINIMALDATA"],
+["0x02 0x0f00", "1", "MINIMALDATA"],
+["0x02 0x1000", "1", "MINIMALDATA"],
+
+["Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test"],
+
+["1 0x02 0x0000", "PICK DROP", ""],
+["1 0x02 0x0000", "ROLL DROP 1", ""],
+["0x02 0x0000", "1ADD DROP 1", ""],
+["0x02 0x0000", "1SUB DROP 1", ""],
+["0x02 0x0000", "NEGATE DROP 1", ""],
+["0x02 0x0000", "ABS DROP 1", ""],
+["0x02 0x0000", "NOT DROP 1", ""],
+["0x02 0x0000", "0NOTEQUAL DROP 1", ""],
+
+["0 0x02 0x0000", "ADD DROP 1", ""],
+["0x02 0x0000 0", "ADD DROP 1", ""],
+["0 0x02 0x0000", "SUB DROP 1", ""],
+["0x02 0x0000 0", "SUB DROP 1", ""],
+["0 0x02 0x0000", "BOOLAND DROP 1", ""],
+["0x02 0x0000 0", "BOOLAND DROP 1", ""],
+["0 0x02 0x0000", "BOOLOR DROP 1", ""],
+["0x02 0x0000 0", "BOOLOR DROP 1", ""],
+["0 0x02 0x0000", "NUMEQUAL DROP 1", ""],
+["0x02 0x0000 1", "NUMEQUAL DROP 1", ""],
+["0 0x02 0x0000", "NUMEQUALVERIFY 1", ""],
+["0x02 0x0000 0", "NUMEQUALVERIFY 1", ""],
+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", ""],
+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", ""],
+["0 0x02 0x0000", "LESSTHAN DROP 1", ""],
+["0x02 0x0000 0", "LESSTHAN DROP 1", ""],
+["0 0x02 0x0000", "GREATERTHAN DROP 1", ""],
+["0x02 0x0000 0", "GREATERTHAN DROP 1", ""],
+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", ""],
+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", ""],
+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", ""],
+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", ""],
+["0 0x02 0x0000", "MIN DROP 1", ""],
+["0x02 0x0000 0", "MIN DROP 1", ""],
+["0 0x02 0x0000", "MAX DROP 1", ""],
+["0x02 0x0000 0", "MAX DROP 1", ""],
+
+["0x02 0x0000 0 0", "WITHIN DROP 1", ""],
+["0 0x02 0x0000 0", "WITHIN DROP 1", ""],
+["0 0 0x02 0x0000", "WITHIN DROP 1", ""],
+
+["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", ""],
+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", ""],
+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", ""],
+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", ""],
+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", ""],
+
+
[
"0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
@@ -638,17 +769,29 @@ nSequences are max.
"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"
],
[
- "0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
+ "1 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
"",
"3-of-3 with nonzero dummy but no NULLDUMMY"
],
[
- "0x01 0x01 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
+ "1 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
"",
"3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
],
+[
+ "0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01 DUP",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+ "",
+ "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"
+],
+[
+ "0 0x47 0x304402203acf75dd59bbef171aeeedae4f1020b824195820db82575c2b323b8899f95de9022067df297d3a5fad049ba0bb81255d0e495643cbcf9abae9e396988618bc0c6dfe01 0x47 0x304402205f8b859230c1cab7d4e8de38ff244d2ebe046b64e8d3f4219b01e483c203490a022071bdc488e31b557f7d9e5c8a8bec90dc92289ca70fa317685f4f140e38b30c4601",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+ "SIGPUSHONLY",
+ "2-of-2 with two identical keys and sigs pushed"
+],
["The End"]
]
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 70a800af51..78c4181409 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core.h"
+#include "core/transaction.h"
#include "main.h"
#include <boost/test/unit_test.hpp>
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index d3fc673a79..a41552fea1 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1,5 +1,5 @@
-// Copyright (c) 2011-2013 The Bitcoin Core developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "data/script_invalid.json.h"
@@ -171,13 +171,15 @@ public:
TestBuilder& Add(const CScript& script)
{
+ DoPush();
spendTx.vin[0].scriptSig += script;
return *this;
}
TestBuilder& Num(int num)
{
- spendTx.vin[0].scriptSig << CScriptNum(num);
+ DoPush();
+ spendTx.vin[0].scriptSig << num;
return *this;
}
@@ -402,6 +404,23 @@ BOOST_AUTO_TEST_CASE(script_build)
"3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
+ good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
+ "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0
+ ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
+ bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
+ "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY
+ ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
+ "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0
+ ).PushSig(keys.key2).PushRedeem());
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
+ "P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY
+ ).PushSig(keys.key2).PushRedeem());
+ good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
+ "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY
+ ).Num(0).PushSig(keys.key1).PushSig(keys.key1));
+
+
std::map<std::string, Array> tests_good;
std::map<std::string, Array> tests_bad;
@@ -769,19 +788,19 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_AUTO_TEST_CASE(script_standard_push)
{
- for (int i=0; i<1000; i++) {
+ for (int i=0; i<67000; i++) {
CScript script;
script << i;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
- BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Number " << i << " push is not canonical.");
+ BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Number " << i << " push is not minimal data.");
}
- for (int i=0; i<1000; i++) {
+ for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) {
std::vector<unsigned char> data(i, '\111');
CScript script;
script << data;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
- BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Length " << i << " push is not canonical.");
+ BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Length " << i << " push is not minimal data.");
}
}
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index ac60fa426f..5621e12729 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -25,11 +25,11 @@ static void CheckCreateVch(const int64_t& num)
BOOST_CHECK(verify(bignum, scriptnum));
CBigNum bignum2(bignum.getvch());
- CScriptNum scriptnum2(scriptnum.getvch());
+ CScriptNum scriptnum2(scriptnum.getvch(), false);
BOOST_CHECK(verify(bignum2, scriptnum2));
CBigNum bignum3(scriptnum2.getvch());
- CScriptNum scriptnum3(bignum2.getvch());
+ CScriptNum scriptnum3(bignum2.getvch(), false);
BOOST_CHECK(verify(bignum3, scriptnum3));
}
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 867a7df888..59e95f2fd1 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "serialize.h"
+#include "streams.h"
#include <stdint.h>
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 41ccaaac94..c46c31e99f 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -33,6 +33,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)
(string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
(string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
+ (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)
+ (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY);
unsigned int ParseScriptFlags(string strFlags)
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 61daa0a3fe..761210feac 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -4,7 +4,7 @@
#include "util.h"
-#include "core.h"
+#include "core/transaction.h"
#include "random.h"
#include "sync.h"
#include "utilstrencodings.h"
diff --git a/src/txdb.cpp b/src/txdb.cpp
index cb9f150011..0731d843f3 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,7 +5,6 @@
#include "txdb.h"
-#include "core.h"
#include "pow.h"
#include "uint256.h"
@@ -104,7 +103,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
/* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it, use a const-cast to get around
that restriction. */
- leveldb::Iterator *pcursor = const_cast<CLevelDBWrapper*>(&db)->NewIterator();
+ boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
pcursor->SeekToFirst();
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 4522c63617..c042dd8467 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -5,7 +5,7 @@
#include "txmempool.h"
-#include "core.h"
+#include "streams.h"
#include "util.h"
#include "utilmoneystr.h"
#include "version.h"
diff --git a/src/txmempool.h b/src/txmempool.h
index ad190eea9d..2ec80cb860 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -8,10 +8,13 @@
#include <list>
+#include "amount.h"
#include "coins.h"
-#include "core.h"
+#include "core/transaction.h"
#include "sync.h"
+class CAutoFile;
+
inline bool AllowFree(double dPriority)
{
// Large (in bytes) low-priority (new, small-coin) transactions
diff --git a/src/undo.h b/src/undo.h
new file mode 100644
index 0000000000..232c193429
--- /dev/null
+++ b/src/undo.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_TXUNDO
+#define H_BITCOIN_TXUNDO
+
+#include "compressor.h"
+#include "core/transaction.h"
+#include "serialize.h"
+
+/** Undo information for a CTxIn
+ *
+ * Contains the prevout's CTxOut being spent, and if this was the
+ * last output of the affected transaction, its metadata as well
+ * (coinbase or not, height, transaction version)
+ */
+class CTxInUndo
+{
+public:
+ CTxOut txout; // the txout data before being spent
+ bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase
+ unsigned int nHeight; // if the outpoint was the last unspent: its height
+ int nVersion; // if the outpoint was the last unspent: its version
+
+ CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {}
+ CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { }
+
+ unsigned int GetSerializeSize(int nType, int nVersion) const {
+ return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) +
+ (nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) +
+ ::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion);
+ }
+
+ template<typename Stream>
+ void Serialize(Stream &s, int nType, int nVersion) const {
+ ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion);
+ if (nHeight > 0)
+ ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
+ ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream &s, int nType, int nVersion) {
+ unsigned int nCode = 0;
+ ::Unserialize(s, VARINT(nCode), nType, nVersion);
+ nHeight = nCode / 2;
+ fCoinBase = nCode & 1;
+ if (nHeight > 0)
+ ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
+ ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion);
+ }
+};
+
+/** Undo information for a CTransaction */
+class CTxUndo
+{
+public:
+ // undo information for all txins
+ std::vector<CTxInUndo> vprevout;
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(vprevout);
+ }
+};
+
+#endif // H_BITCOIN_TXUNDO
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 95be06aa18..267a5b845c 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -5,7 +5,7 @@
#include "utilmoneystr.h"
-#include "core.h"
+#include "core/transaction.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 65944587f8..3812c22fe2 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -2298,7 +2298,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
return chainActive.Height() - pindex->nHeight + 1;
}
-int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
+int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const
{
if (hashBlock == 0 || nIndex == -1)
return 0;
@@ -2324,7 +2324,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
return chainActive.Height() - pindex->nHeight + 1;
}
-int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
+int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
{
AssertLockHeld(cs_main);
int nResult = GetDepthInMainChainINTERNAL(pindexRet);
diff --git a/src/wallet.h b/src/wallet.h
index 06706655f8..768887e0cb 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -6,7 +6,9 @@
#ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H
-#include "core.h"
+#include "amount.h"
+#include "core/block.h"
+#include "core/transaction.h"
#include "crypter.h"
#include "key.h"
#include "keystore.h"
@@ -474,7 +476,7 @@ struct COutputEntry
class CMerkleTx : public CTransaction
{
private:
- int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const;
+ int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
public:
uint256 hashBlock;
@@ -519,9 +521,9 @@ public:
// -1 : not in blockchain, and not in memory pool (conflicted transaction)
// 0 : in memory pool, waiting to be included in a block
// >=1 : this many blocks deep in the main chain
- int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
- int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
- bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
+ int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
+ int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
+ bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
int GetBlocksToMaturity() const;
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true);
};