aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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.cpp5
-rw-r--r--src/chain.h77
-rw-r--r--src/chainparams.cpp91
-rw-r--r--src/chainparams.h42
-rw-r--r--src/chainparamsbase.cpp27
-rw-r--r--src/chainparamsbase.h2
-rw-r--r--src/chainparamsseeds.h11
-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.cpp8
-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/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/netbase.cpp19
-rw-r--r--src/netbase.h3
-rw-r--r--src/pow.cpp2
-rw-r--r--src/qt/bitcoingui.cpp24
-rw-r--r--src/qt/bitcoingui.h6
-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
81 files changed, 2643 insertions, 2125 deletions
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.cpp b/src/chain.cpp
index 56ed22ce71..e13c047861 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -7,8 +7,9 @@
using namespace std;
-// CChain implementation
-
+/**
+ * CChain implementation
+ */
void CChain::SetTip(CBlockIndex *pindex) {
if (pindex == NULL) {
vChain.clear();
diff --git a/src/chain.h b/src/chain.h
index 290150476e..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"
@@ -50,38 +50,40 @@ struct CDiskBlockPos
};
enum BlockStatus {
- // Unused.
+ //! Unused.
BLOCK_VALID_UNKNOWN = 0,
- // Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
+ //! Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
BLOCK_VALID_HEADER = 1,
- // All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents
- // are also at least TREE.
+ //! All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents
+ //! are also at least TREE.
BLOCK_VALID_TREE = 2,
- // Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids,
- // sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all
- // parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set.
+ /**
+ * Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids,
+ * sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all
+ * parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set.
+ */
BLOCK_VALID_TRANSACTIONS = 3,
- // Outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30.
- // Implies all parents are also at least CHAIN.
+ //! Outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30.
+ //! Implies all parents are also at least CHAIN.
BLOCK_VALID_CHAIN = 4,
- // Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
+ //! Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
BLOCK_VALID_SCRIPTS = 5,
- // All validity bits.
+ //! All validity bits.
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
- BLOCK_HAVE_DATA = 8, // full block available in blk*.dat
- BLOCK_HAVE_UNDO = 16, // undo data available in rev*.dat
+ BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat
+ BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat
BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,
- BLOCK_FAILED_VALID = 32, // stage after last reached validness failed
- BLOCK_FAILED_CHILD = 64, // descends from failed block
+ BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
+ BLOCK_FAILED_CHILD = 64, //! descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
};
@@ -93,49 +95,50 @@ enum BlockStatus {
class CBlockIndex
{
public:
- // pointer to the hash of the block, if any. memory is owned by this CBlockIndex
+ //! pointer to the hash of the block, if any. memory is owned by this CBlockIndex
const uint256* phashBlock;
- // pointer to the index of the predecessor of this block
+ //! pointer to the index of the predecessor of this block
CBlockIndex* pprev;
- // pointer to the index of some further predecessor of this block
+ //! pointer to the index of some further predecessor of this block
CBlockIndex* pskip;
- // height of the entry in the chain. The genesis block has height 0
+ //! height of the entry in the chain. The genesis block has height 0
int nHeight;
- // Which # file this block is stored in (blk?????.dat)
+ //! Which # file this block is stored in (blk?????.dat)
int nFile;
- // Byte offset within blk?????.dat where this block's data is stored
+ //! Byte offset within blk?????.dat where this block's data is stored
unsigned int nDataPos;
- // Byte offset within rev?????.dat where this block's undo data is stored
+ //! Byte offset within rev?????.dat where this block's undo data is stored
unsigned int nUndoPos;
- // (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
+ //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
uint256 nChainWork;
- // Number of transactions in this block.
- // Note: in a potential headers-first mode, this number cannot be relied upon
+ //! Number of transactions in this block.
+ //! Note: in a potential headers-first mode, this number cannot be relied upon
unsigned int nTx;
- // (memory only) Number of transactions in the chain up to and including this block.
- // This value will be non-zero only if and only if transactions for this block and all its parents are available.
- unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030
+ //! (memory only) Number of transactions in the chain up to and including this block.
+ //! This value will be non-zero only if and only if transactions for this block and all its parents are available.
+ //! Change to 64-bit type when necessary; won't happen before 2030
+ unsigned int nChainTx;
- // Verification status of this block. See enum BlockStatus
+ //! Verification status of this block. See enum BlockStatus
unsigned int nStatus;
- // block header
+ //! block header
int nVersion;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
- // (memory only) Sequencial id assigned to distinguish order in which blocks are received.
+ //! (memory only) Sequential id assigned to distinguish order in which blocks are received.
uint32_t nSequenceId;
void SetNull()
@@ -254,7 +257,7 @@ public:
GetBlockHash().ToString());
}
- // Check whether this block index entry is valid up to the passed validity level.
+ //! Check whether this block index entry is valid up to the passed validity level.
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
{
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
@@ -263,8 +266,8 @@ public:
return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);
}
- // Raise the validity level of this block index entry.
- // Returns true if the validity was changed.
+ //! Raise the validity level of this block index entry.
+ //! Returns true if the validity was changed.
bool RaiseValidity(enum BlockStatus nUpTo)
{
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
@@ -277,10 +280,10 @@ public:
return false;
}
- // Build the skiplist pointer for this entry.
+ //! Build the skiplist pointer for this entry.
void BuildSkip();
- // Efficiently find an ancestor of this block.
+ //! Efficiently find an ancestor of this block.
CBlockIndex* GetAncestor(int height);
const CBlockIndex* GetAncestor(int height) const;
};
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 1ab292517a..9ffc369b40 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2010 Satoshi Nakamoto
// 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 "chainparams.h"
@@ -23,11 +23,11 @@ struct SeedSpec6 {
#include "chainparamsseeds.h"
-//
-// Main network
-//
+/**
+ * Main network
+ */
-// Convert the pnSeeds6 array into usable address objects.
+//! Convert the pnSeeds6 array into usable address objects.
static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data, unsigned int count)
{
// It'll only connect to one or two seed nodes because once it connects,
@@ -45,11 +45,13 @@ static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data
}
}
- // What makes a good checkpoint block?
- // + Is surrounded by blocks with reasonable timestamps
- // (no blocks before with a timestamp after, none after with
- // timestamp before)
- // + Contains no strange transactions
+/**
+ * What makes a good checkpoint block?
+ * + Is surrounded by blocks with reasonable timestamps
+ * (no blocks before with a timestamp after, none after with
+ * timestamp before)
+ * + Contains no strange transactions
+ */
static Checkpoints::MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
@@ -101,9 +103,11 @@ public:
CMainParams() {
networkID = CBaseChainParams::MAIN;
strNetworkID = "main";
- // The message start string is designed to be unlikely to occur in normal data.
- // The characters are rarely used upper ASCII, not valid as UTF-8, and produce
- // a large 4-byte int at any alignment.
+ /**
+ * The message start string is designed to be unlikely to occur in normal data.
+ * The characters are rarely used upper ASCII, not valid as UTF-8, and produce
+ * a large 4-byte int at any alignment.
+ */
pchMessageStart[0] = 0xf9;
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
@@ -119,14 +123,16 @@ public:
nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
nTargetSpacing = 10 * 60;
- // Build the genesis block. Note that the output of the genesis coinbase cannot
- // be spent as it did not originally exist in the database.
- //
- // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
- // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
- // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
- // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
- // vMerkleTree: 4a5e1e
+ /**
+ * Build the genesis block. Note that the output of the genesis coinbase cannot
+ * be spent as it did not originally exist in the database.
+ *
+ * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
+ * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
+ * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
+ * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
+ * vMerkleTree: 4a5e1e
+ */
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CMutableTransaction txNew;
txNew.vin.resize(1);
@@ -178,18 +184,19 @@ public:
};
static CMainParams mainParams;
-//
-// Testnet (v3)
-//
-
+/**
+ * Testnet (v3)
+ */
class CTestNetParams : public CMainParams {
public:
CTestNetParams() {
networkID = CBaseChainParams::TESTNET;
strNetworkID = "test";
- // The message start string is designed to be unlikely to occur in normal data.
- // The characters are rarely used upper ASCII, not valid as UTF-8, and produce
- // a large 4-byte int at any alignment.
+ /**
+ * The message start string is designed to be unlikely to occur in normal data.
+ * The characters are rarely used upper ASCII, not valid as UTF-8, and produce
+ * a large 4-byte int at any alignment.
+ */
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
@@ -200,10 +207,10 @@ public:
nRejectBlockOutdatedMajority = 75;
nToCheckBlockUpgradeMajority = 100;
nMinerThreads = 0;
- nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ nTargetTimespan = 14 * 24 * 60 * 60; //! two weeks
nTargetSpacing = 10 * 60;
- // Modify the testnet genesis block so the timestamp is valid for a later start.
+ //! Modify the testnet genesis block so the timestamp is valid for a later start.
genesis.nTime = 1296688602;
genesis.nNonce = 414098458;
hashGenesisBlock = genesis.GetHash();
@@ -239,9 +246,9 @@ public:
};
static CTestNetParams testNetParams;
-//
-// Regression test
-//
+/**
+ * Regression test
+ */
class CRegTestParams : public CTestNetParams {
public:
CRegTestParams() {
@@ -256,7 +263,7 @@ public:
nRejectBlockOutdatedMajority = 950;
nToCheckBlockUpgradeMajority = 1000;
nMinerThreads = 1;
- nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ nTargetTimespan = 14 * 24 * 60 * 60; //! two weeks
nTargetSpacing = 10 * 60;
bnProofOfWorkLimit = ~uint256(0) >> 1;
genesis.nTime = 1296688602;
@@ -266,8 +273,8 @@ public:
nDefaultPort = 18444;
assert(hashGenesisBlock == uint256("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
- vFixedSeeds.clear(); // Regtest mode doesn't have any fixed seeds.
- vSeeds.clear(); // Regtest mode doesn't have any DNS seeds.
+ vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
+ vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds.
fRequireRPCPassword = false;
fMiningRequiresPeers = false;
@@ -284,17 +291,17 @@ public:
};
static CRegTestParams regTestParams;
-//
-// Unit test
-//
+/**
+ * Unit test
+ */
class CUnitTestParams : public CMainParams, public CModifiableParams {
public:
CUnitTestParams() {
networkID = CBaseChainParams::UNITTEST;
strNetworkID = "unittest";
nDefaultPort = 18445;
- vFixedSeeds.clear();
- vSeeds.clear(); // Regtest mode doesn't have any DNS seeds.
+ vFixedSeeds.clear(); //! Unit test mode doesn't have any fixed seeds.
+ vSeeds.clear(); //! Unit test mode doesn't have any DNS seeds.
fRequireRPCPassword = false;
fMiningRequiresPeers = false;
@@ -309,7 +316,7 @@ public:
return data;
}
- // Published setters to allow changing values in unit test cases
+ //! Published setters to allow changing values in unit test cases
virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval=anSubsidyHalvingInterval; }
virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority=anEnforceBlockUpgradeMajority; }
virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) { nRejectBlockOutdatedMajority=anRejectBlockOutdatedMajority; }
diff --git a/src/chainparams.h b/src/chainparams.h
index f157419bb2..9279edd6c0 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -1,14 +1,14 @@
// 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_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"
@@ -47,34 +47,33 @@ public:
int GetDefaultPort() const { return nDefaultPort; }
const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; }
int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; }
- /* Used to check majorities for block version upgrade */
+ /** Used to check majorities for block version upgrade */
int EnforceBlockUpgradeMajority() const { return nEnforceBlockUpgradeMajority; }
int RejectBlockOutdatedMajority() const { return nRejectBlockOutdatedMajority; }
int ToCheckBlockUpgradeMajority() const { return nToCheckBlockUpgradeMajority; }
- /* Used if GenerateBitcoins is called with a negative number of threads */
+ /** Used if GenerateBitcoins is called with a negative number of threads */
int DefaultMinerThreads() const { return nMinerThreads; }
const CBlock& GenesisBlock() const { return genesis; }
bool RequireRPCPassword() const { return fRequireRPCPassword; }
- /* Make miner wait to have peers to avoid wasting work */
+ /** Make miner wait to have peers to avoid wasting work */
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
- /* Default value for -checkmempool argument */
+ /** Default value for -checkmempool argument */
bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; }
- /* Allow mining of a min-difficulty block */
+ /** Allow mining of a min-difficulty block */
bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; }
- /* Skip proof-of-work check: allow mining of any difficulty block */
+ /** Skip proof-of-work check: allow mining of any difficulty block */
bool SkipProofOfWorkCheck() const { return fSkipProofOfWorkCheck; }
- /* Make standard checks */
+ /** Make standard checks */
bool RequireStandard() const { return fRequireStandard; }
int64_t TargetTimespan() const { return nTargetTimespan; }
int64_t TargetSpacing() const { return nTargetSpacing; }
int64_t Interval() const { return nTargetTimespan / nTargetSpacing; }
- /* Make miner stop after a block is found. In RPC, don't return
- * until nGenProcLimit blocks are generated */
+ /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
- /* In the future use NetworkIDString() for RPC fields */
+ /** In the future use NetworkIDString() for RPC fields */
bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
- /* Return the BIP70 network string (main, test or regtest) */
+ /** Return the BIP70 network string (main, test or regtest) */
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
@@ -85,7 +84,7 @@ protected:
uint256 hashGenesisBlock;
MessageStartChars pchMessageStart;
- // Raw pub key bytes for the broadcast alert signing key.
+ //! Raw pub key bytes for the broadcast alert signing key.
std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
uint256 bnProofOfWorkLimit;
@@ -112,14 +111,15 @@ protected:
bool fTestnetToBeDeprecatedFieldRPC;
};
-/** Modifiable parameters interface is used by test cases to adapt the parameters in order
-*** to test specific features more easily. Test cases should always restore the previous
-*** values after finalization.
-**/
+/**
+ * Modifiable parameters interface is used by test cases to adapt the parameters in order
+ * to test specific features more easily. Test cases should always restore the previous
+ * values after finalization.
+ */
class CModifiableParams {
public:
- // Published setters to allow changing values in unit test cases
+ //! Published setters to allow changing values in unit test cases
virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) =0;
virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority)=0;
virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority)=0;
@@ -139,7 +139,7 @@ const CChainParams &Params();
/** Return parameters for the given network. */
CChainParams &Params(CBaseChainParams::Network network);
-/** Get modifyable network parameters (UNITTEST only) */
+/** Get modifiable network parameters (UNITTEST only) */
CModifiableParams *ModifiableParams();
/** Sets the params returned by Params() to those for the given network. */
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 5d9ec7927b..8646a31603 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2010 Satoshi Nakamoto
// 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 "chainparamsbase.h"
@@ -13,10 +13,9 @@
using namespace boost::assign;
-//
-// Main network
-//
-
+/**
+ * Main network
+ */
class CBaseMainParams : public CBaseChainParams
{
public:
@@ -28,9 +27,9 @@ public:
};
static CBaseMainParams mainParams;
-//
-// Testnet (v3)
-//
+/**
+ * Testnet (v3)
+ */
class CBaseTestNetParams : public CBaseMainParams
{
public:
@@ -43,9 +42,9 @@ public:
};
static CBaseTestNetParams testNetParams;
-//
-// Regression test
-//
+/*
+ * Regression test
+ */
class CBaseRegTestParams : public CBaseTestNetParams
{
public:
@@ -57,9 +56,9 @@ public:
};
static CBaseRegTestParams regTestParams;
-//
-// Unit test
-//
+/*
+ * Unit test
+ */
class CBaseUnitTestParams : public CBaseMainParams
{
public:
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 911d1181ac..4042b8c879 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -1,5 +1,5 @@
// Copyright (c) 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.
#ifndef BITCOIN_CHAIN_PARAMS_BASE_H
diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h
index 3f3278361e..c3323c48bd 100644
--- a/src/chainparamsseeds.h
+++ b/src/chainparamsseeds.h
@@ -1,10 +1,13 @@
#ifndef H_CHAINPARAMSSEEDS
#define H_CHAINPARAMSSEEDS
-// List of fixed seed nodes for the bitcoin network
-// AUTOGENERATED by contrib/devtools/generate-seeds.py
-// Each line contains a 16-byte IPv6 address and a port.
-// IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.
+/**
+ * List of fixed seed nodes for the bitcoin network
+ * AUTOGENERATED by contrib/devtools/generate-seeds.py
+ *
+ * Each line contains a 16-byte IPv6 address and a port.
+ * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.
+ */
static SeedSpec6 pnSeed6_main[] = {
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x69,0x6a,0x7e}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x04,0x7d}, 8333},
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..3fd08ce006 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"
@@ -547,6 +548,10 @@ bool AppInit2(boost::thread_group& threadGroup)
#endif
// ********************************************************* Step 2: parameter interactions
+ // Set this early so that parameter interactions go to console
+ fPrintToConsole = GetBoolArg("-printtoconsole", false);
+ fLogTimestamps = GetBoolArg("-logtimestamps", true);
+ fLogIPs = GetBoolArg("-logips", false);
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
// when specifying an explicit binding address, you want to listen on it
@@ -640,9 +645,6 @@ bool AppInit2(boost::thread_group& threadGroup)
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
fServer = GetBoolArg("-server", false);
- fPrintToConsole = GetBoolArg("-printtoconsole", false);
- fLogTimestamps = GetBoolArg("-logtimestamps", true);
- fLogIPs = GetBoolArg("-logips", false);
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
#endif
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/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/netbase.cpp b/src/netbase.cpp
index b3d1001547..ea05b8766f 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -667,11 +667,28 @@ bool CNetAddr::IsRFC1918() const
(GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
}
+bool CNetAddr::IsRFC2544() const
+{
+ return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19);
+}
+
bool CNetAddr::IsRFC3927() const
{
return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
}
+bool CNetAddr::IsRFC6598() const
+{
+ return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127;
+}
+
+bool CNetAddr::IsRFC5737() const
+{
+ return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||
+ (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||
+ (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));
+}
+
bool CNetAddr::IsRFC3849() const
{
return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;
@@ -778,7 +795,7 @@ bool CNetAddr::IsValid() const
bool CNetAddr::IsRoutable() const
{
- return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
+ return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
}
enum Network CNetAddr::GetNetwork() const
diff --git a/src/netbase.h b/src/netbase.h
index 1455cd8c33..9d8697dcc6 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -61,6 +61,9 @@ class CNetAddr
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
+ bool IsRFC2544() const; // IPv4 inter-network communcations (192.18.0.0/15)
+ bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10)
+ bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24)
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
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/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index f0471c32f9..77cfdceef0 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -19,7 +19,7 @@
#ifdef ENABLE_WALLET
#include "walletframe.h"
#include "walletmodel.h"
-#endif
+#endif // ENABLE_WALLET
#ifdef Q_OS_MAC
#include "macdockiconhandler.h"
@@ -106,7 +106,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
bool enableWallet = !GetBoolArg("-disablewallet", false);
#else
bool enableWallet = false;
-#endif
+#endif // ENABLE_WALLET
if(enableWallet)
{
windowTitle += tr("Wallet");
@@ -136,7 +136,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
walletFrame = new WalletFrame(this);
setCentralWidget(walletFrame);
} else
-#endif
+#endif // ENABLE_WALLET
{
/* When compiled without wallet or -disablewallet is provided,
* the central widget is the rpc console.
@@ -268,6 +268,7 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
tabGroup->addAction(historyAction);
+#ifdef ENABLE_WALLET
// These showNormalIfMinimized are needed because Send Coins and Receive Coins
// can be triggered from the tray menu, and need to show the GUI to be useful.
connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
@@ -278,6 +279,7 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
+#endif // ENABLE_WALLET
quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
quitAction->setStatusTip(tr("Quit application"));
@@ -343,7 +345,7 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle)
connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses()));
connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked()));
}
-#endif
+#endif // ENABLE_WALLET
}
void BitcoinGUI::createMenuBar()
@@ -433,7 +435,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
{
walletFrame->setClientModel(clientModel);
}
-#endif
+#endif // ENABLE_WALLET
unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
} else {
// Disable possibility to show main window via action
@@ -469,7 +471,7 @@ void BitcoinGUI::removeAllWallets()
setWalletActionsEnabled(false);
walletFrame->removeAllWallets();
}
-#endif
+#endif // ENABLE_WALLET
void BitcoinGUI::setWalletActionsEnabled(bool enabled)
{
@@ -616,7 +618,7 @@ void BitcoinGUI::gotoVerifyMessageTab(QString addr)
{
if (walletFrame) walletFrame->gotoVerifyMessageTab(addr);
}
-#endif
+#endif // ENABLE_WALLET
void BitcoinGUI::setNumConnections(int count)
{
@@ -676,7 +678,7 @@ void BitcoinGUI::setNumBlocks(int count)
#ifdef ENABLE_WALLET
if(walletFrame)
walletFrame->showOutOfSyncWarning(false);
-#endif
+#endif // ENABLE_WALLET
progressBarLabel->setVisible(false);
progressBar->setVisible(false);
@@ -727,7 +729,7 @@ void BitcoinGUI::setNumBlocks(int count)
#ifdef ENABLE_WALLET
if(walletFrame)
walletFrame->showOutOfSyncWarning(true);
-#endif
+#endif // ENABLE_WALLET
tooltip += QString("<br>");
tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
@@ -850,7 +852,7 @@ void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmoun
.arg(type)
.arg(address), CClientUIInterface::MSG_INFORMATION);
}
-#endif
+#endif // ENABLE_WALLET
void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
{
@@ -924,7 +926,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
break;
}
}
-#endif
+#endif // ENABLE_WALLET
void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
{
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index f65f0e9137..0ef4101127 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -63,7 +63,7 @@ public:
bool addWallet(const QString& name, WalletModel *walletModel);
bool setCurrentWallet(const QString& name);
void removeAllWallets();
-#endif
+#endif // ENABLE_WALLET
protected:
void changeEvent(QEvent *e);
@@ -163,7 +163,7 @@ public slots:
/** Show incoming transaction notification for new transactions. */
void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address);
-#endif
+#endif // ENABLE_WALLET
private slots:
#ifdef ENABLE_WALLET
@@ -183,7 +183,7 @@ private slots:
/** Show open dialog */
void openClicked();
-#endif
+#endif // ENABLE_WALLET
/** Show configuration dialog */
void optionsClicked();
/** Show about dialog */
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);
};