aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am22
-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/bloom.cpp1
-rw-r--r--src/core_read.cpp1
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/db.h1
-rw-r--r--src/ecwrapper.cpp333
-rw-r--r--src/ecwrapper.h46
-rw-r--r--src/key.cpp366
-rw-r--r--src/leveldbwrapper.h1
-rw-r--r--src/net.h1
-rw-r--r--src/qt/recentrequeststablemodel.cpp1
-rw-r--r--src/rpcblockchain.cpp3
-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/serialize_tests.cpp1
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txmempool.cpp1
-rw-r--r--src/txmempool.h2
-rw-r--r--src/wallet.cpp4
-rw-r--r--src/wallet.h8
26 files changed, 1017 insertions, 914 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 155adfef7d..1f8f9aabdc 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
@@ -82,6 +84,7 @@ BITCOIN_CORE_H = \
core_io.h \
crypter.h \
db.h \
+ ecwrapper.h \
hash.h \
init.h \
key.h \
@@ -107,6 +110,7 @@ BITCOIN_CORE_H = \
script/sign.h \
script/standard.h \
serialize.h \
+ streams.h \
sync.h \
threadsafety.h \
timedata.h \
@@ -211,6 +215,7 @@ libbitcoin_common_a_SOURCES = \
core.cpp \
core_read.cpp \
core_write.cpp \
+ ecwrapper.cpp \
hash.cpp \
key.cpp \
keystore.cpp \
@@ -281,7 +286,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 +298,8 @@ bitcoin_cli_LDADD = \
$(LIBBITCOIN_CRYPTO) \
$(BOOST_LIBS) \
$(SSL_LIBS) \
- $(CRYPTO_LIBS)
+ $(CRYPTO_LIBS) \
+ $(MINIUPNPC_LIBS)
bitcoin_cli_SOURCES = \
bitcoin-cli.cpp
@@ -317,7 +323,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/bloom.cpp b/src/bloom.cpp
index cef74a3a54..cac71fdbbf 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -7,6 +7,7 @@
#include "core.h"
#include "script/script.h"
#include "script/standard.h"
+#include "streams.h"
#include <math.h>
#include <stdlib.h>
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 8b85a03c54..dcbcf4b4f7 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -7,6 +7,7 @@
#include "core.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..b2b29fb367 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -9,6 +9,7 @@
#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/key.cpp b/src/key.cpp
index 079e2c6540..0f4bc6652c 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -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) {
@@ -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/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/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/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/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/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/txdb.cpp b/src/txdb.cpp
index cb9f150011..8a73ce961c 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -104,7 +104,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..b0d6b4aefa 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -6,6 +6,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..85cf5310ff 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -12,6 +12,8 @@
#include "core.h"
#include "sync.h"
+class CAutoFile;
+
inline bool AllowFree(double dPriority)
{
// Large (in bytes) low-priority (new, small-coin) transactions
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..9b6895090c 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -474,7 +474,7 @@ struct COutputEntry
class CMerkleTx : public CTransaction
{
private:
- int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const;
+ int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
public:
uint256 hashBlock;
@@ -519,9 +519,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);
};