aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@bitpay.com>2013-06-10 06:17:38 -0700
committerJeff Garzik <jgarzik@bitpay.com>2013-06-10 06:17:38 -0700
commitf59530ce6eb5a889e6eb750024ddb20e7b0df9d7 (patch)
treee224b540dce7890cbf54f43215a05213bd5cb494
parent8b313c93311813e8697807a701604d182ee83d44 (diff)
parent6e68524e95da2bedc21b1d95c4a206b902ab7c22 (diff)
Merge pull request #2154 from CodeShark/dependencycleanup
Clean up code dependencies
-rw-r--r--bitcoin-qt.pro2
-rw-r--r--src/core.cpp7
-rw-r--r--src/core.h736
-rw-r--r--src/db.cpp11
-rw-r--r--src/db.h10
-rw-r--r--src/init.cpp9
-rw-r--r--src/main.cpp331
-rw-r--r--src/main.h868
-rw-r--r--src/makefile.linux-mingw1
-rw-r--r--src/makefile.mingw1
-rw-r--r--src/makefile.osx1
-rw-r--r--src/makefile.unix1
-rw-r--r--src/net.cpp28
-rw-r--r--src/net.h15
-rw-r--r--src/protocol.cpp1
-rw-r--r--src/qt/transactiondesc.cpp4
-rw-r--r--src/qt/transactionrecord.cpp4
-rw-r--r--src/rpcmining.cpp4
-rw-r--r--src/rpcrawtransaction.cpp2
-rw-r--r--src/rpcwallet.cpp10
-rw-r--r--src/script.cpp2
-rw-r--r--src/script.h2
-rw-r--r--src/test/data/tx_invalid.json2
-rw-r--r--src/test/data/tx_valid.json2
-rw-r--r--src/test/script_P2SH_tests.cpp18
-rw-r--r--src/test/transaction_tests.cpp24
-rw-r--r--src/wallet.cpp16
-rw-r--r--src/wallet.h8
-rw-r--r--src/walletdb.cpp2
-rw-r--r--src/walletdb.h4
30 files changed, 1103 insertions, 1023 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index 9addf6d5ea..8f49dccee3 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -154,6 +154,7 @@ HEADERS += src/qt/bitcoingui.h \
src/hash.h \
src/uint256.h \
src/serialize.h \
+ src/core.h \
src/main.h \
src/net.h \
src/key.h \
@@ -233,6 +234,7 @@ SOURCES += src/qt/bitcoin.cpp \
src/netbase.cpp \
src/key.cpp \
src/script.cpp \
+ src/core.cpp \
src/main.cpp \
src/init.cpp \
src/net.cpp \
diff --git a/src/core.cpp b/src/core.cpp
new file mode 100644
index 0000000000..b12c90efe8
--- /dev/null
+++ b/src/core.cpp
@@ -0,0 +1,7 @@
+// 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.
+
+#include "core.h"
+
diff --git a/src/core.h b/src/core.h
new file mode 100644
index 0000000000..cba3ab233f
--- /dev/null
+++ b/src/core.h
@@ -0,0 +1,736 @@
+// 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 "uint256.h"
+#include "serialize.h"
+#include "util.h"
+#include "script.h"
+
+#include <stdio.h>
+
+class CTransaction;
+
+/** An outpoint - a combination of a transaction hash and an index n into its vout */
+class COutPoint
+{
+public:
+ uint256 hash;
+ unsigned int n;
+
+ COutPoint() { SetNull(); }
+ COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
+ IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
+ void SetNull() { hash = 0; n = (unsigned int) -1; }
+ bool IsNull() const { return (hash == 0 && n == (unsigned int) -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
+ {
+ return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n);
+ }
+
+ void print() const
+ {
+ printf("%s\n", ToString().c_str());
+ }
+};
+
+/** An inpoint - a combination of a transaction and an index n into its vin */
+class CInPoint
+{
+public:
+ CTransaction* ptx;
+ unsigned int n;
+
+ CInPoint() { SetNull(); }
+ CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
+ void SetNull() { ptx = NULL; n = (unsigned int) -1; }
+ bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
+};
+
+/** 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;
+ unsigned int nSequence;
+
+ CTxIn()
+ {
+ nSequence = std::numeric_limits<unsigned int>::max();
+ }
+
+ explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
+ {
+ prevout = prevoutIn;
+ scriptSig = scriptSigIn;
+ nSequence = nSequenceIn;
+ }
+
+ CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
+ {
+ prevout = COutPoint(hashPrevTx, nOut);
+ scriptSig = scriptSigIn;
+ nSequence = nSequenceIn;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(prevout);
+ READWRITE(scriptSig);
+ READWRITE(nSequence);
+ )
+
+ bool IsFinal() const
+ {
+ return (nSequence == std::numeric_limits<unsigned int>::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
+ {
+ std::string str;
+ str += "CTxIn(";
+ str += prevout.ToString();
+ if (prevout.IsNull())
+ str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
+ else
+ str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
+ if (nSequence != std::numeric_limits<unsigned int>::max())
+ str += strprintf(", nSequence=%u", nSequence);
+ str += ")";
+ return str;
+ }
+
+ void print() const
+ {
+ printf("%s\n", ToString().c_str());
+ }
+};
+
+
+
+
+/** 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:
+ int64 nValue;
+ CScript scriptPubKey;
+
+ CTxOut()
+ {
+ SetNull();
+ }
+
+ CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
+ {
+ nValue = nValueIn;
+ scriptPubKey = scriptPubKeyIn;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(nValue);
+ READWRITE(scriptPubKey);
+ )
+
+ void SetNull()
+ {
+ nValue = -1;
+ scriptPubKey.clear();
+ }
+
+ bool IsNull() const
+ {
+ return (nValue == -1);
+ }
+
+ uint256 GetHash() const
+ {
+ return SerializeHash(*this);
+ }
+
+ bool IsDust(int64 nMinRelayTxFee) const
+ {
+ // "Dust" is defined in terms of CTransaction::nMinRelayTxFee,
+ // 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 33 bytes big, and will
+ // need a CTxIn of at least 148 bytes to spend,
+ // so dust is a txout less than 54 uBTC
+ // (5430 satoshis) with default nMinRelayTxFee
+ return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < nMinRelayTxFee);
+ }
+
+ 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
+ {
+ if (scriptPubKey.size() < 6)
+ return "CTxOut(error)";
+ return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
+ }
+
+ void print() const
+ {
+ printf("%s\n", ToString().c_str());
+ }
+};
+
+
+/** The basic transaction that is broadcasted on the network and contained in
+ * blocks. A transaction can contain multiple inputs and outputs.
+ */
+class CTransaction
+{
+public:
+ static int64 nMinTxFee;
+ static int64 nMinRelayTxFee;
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+ std::vector<CTxIn> vin;
+ std::vector<CTxOut> vout;
+ unsigned int nLockTime;
+
+ CTransaction()
+ {
+ SetNull();
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(vin);
+ READWRITE(vout);
+ READWRITE(nLockTime);
+ )
+
+ void SetNull()
+ {
+ nVersion = CTransaction::CURRENT_VERSION;
+ vin.clear();
+ vout.clear();
+ nLockTime = 0;
+ }
+
+ bool IsNull() const
+ {
+ return (vin.empty() && vout.empty());
+ }
+
+ uint256 GetHash() const
+ {
+ return SerializeHash(*this);
+ }
+
+ bool IsNewerThan(const CTransaction& old) const
+ {
+ if (vin.size() != old.vin.size())
+ return false;
+ for (unsigned int i = 0; i < vin.size(); i++)
+ if (vin[i].prevout != old.vin[i].prevout)
+ return false;
+
+ bool fNewer = false;
+ unsigned int nLowest = std::numeric_limits<unsigned int>::max();
+ for (unsigned int i = 0; i < vin.size(); i++)
+ {
+ if (vin[i].nSequence != old.vin[i].nSequence)
+ {
+ if (vin[i].nSequence <= nLowest)
+ {
+ fNewer = false;
+ nLowest = vin[i].nSequence;
+ }
+ if (old.vin[i].nSequence < nLowest)
+ {
+ fNewer = true;
+ nLowest = old.vin[i].nSequence;
+ }
+ }
+ }
+ return fNewer;
+ }
+
+ bool IsCoinBase() const
+ {
+ return (vin.size() == 1 && vin[0].prevout.IsNull());
+ }
+
+ friend bool operator==(const CTransaction& a, const CTransaction& b)
+ {
+ return (a.nVersion == b.nVersion &&
+ a.vin == b.vin &&
+ a.vout == b.vout &&
+ a.nLockTime == b.nLockTime);
+ }
+
+ friend bool operator!=(const CTransaction& a, const CTransaction& b)
+ {
+ return !(a == b);
+ }
+
+
+ std::string ToString() const
+ {
+ std::string str;
+ str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n",
+ GetHash().ToString().substr(0,10).c_str(),
+ 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;
+ }
+
+ void print() const
+ {
+ printf("%s", ToString().c_str());
+ }
+};
+
+/** wrapper for CTxOut that provides a more compact serialization */
+class CTxOutCompressor
+{
+private:
+ CTxOut &txout;
+
+public:
+ static uint64 CompressAmount(uint64 nAmount);
+ static uint64 DecompressAmount(uint64 nAmount);
+
+ CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
+
+ IMPLEMENT_SERIALIZE(({
+ if (!fRead) {
+ uint64 nVal = CompressAmount(txout.nValue);
+ READWRITE(VARINT(nVal));
+ } else {
+ uint64 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;
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(vprevout);
+ )
+};
+
+
+/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
+ *
+ * Serialized format:
+ * - VARINT(nVersion)
+ * - VARINT(nCode)
+ * - unspentness bitvector, for vout[2] and further; least significant byte first
+ * - the non-spent CTxOuts (via CTxOutCompressor)
+ * - VARINT(nHeight)
+ *
+ * The nCode value consists of:
+ * - bit 1: IsCoinBase()
+ * - bit 2: vout[0] is not spent
+ * - bit 4: vout[1] is not spent
+ * - The higher bits encode N, the number of non-zero bytes in the following bitvector.
+ * - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at
+ * least one non-spent output).
+ *
+ * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e
+ * <><><--------------------------------------------><---->
+ * | \ | /
+ * version code vout[1] height
+ *
+ * - version = 1
+ * - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
+ * - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
+ * - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
+ * * 8358: compact amount representation for 60000000000 (600 BTC)
+ * * 00: special txout type pay-to-pubkey-hash
+ * * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
+ * - height = 203998
+ *
+ *
+ * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b
+ * <><><--><--------------------------------------------------><----------------------------------------------><---->
+ * / \ \ | | /
+ * version code unspentness vout[4] vout[16] height
+ *
+ * - version = 1
+ * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
+ * 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
+ * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
+ * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
+ * * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)
+ * * 00: special txout type pay-to-pubkey-hash
+ * * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
+ * - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
+ * * bbd123: compact amount representation for 110397 (0.001 BTC)
+ * * 00: special txout type pay-to-pubkey-hash
+ * * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
+ * - height = 120891
+ */
+class CCoins
+{
+public:
+ // whether transaction is a coinbase
+ bool fCoinBase;
+
+ // unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
+ std::vector<CTxOut> vout;
+
+ // at which height this transaction was included in the active block chain
+ int nHeight;
+
+ // version of the CTransaction; accesses to this value should probably check for nHeight as well,
+ // as new tx version will probably only be introduced at certain heights
+ int nVersion;
+
+ // construct a CCoins from a CTransaction, at a given height
+ CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) { }
+
+ // empty constructor
+ CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { }
+
+ // remove spent outputs at the end of vout
+ void Cleanup() {
+ while (vout.size() > 0 && vout.back().IsNull())
+ vout.pop_back();
+ if (vout.empty())
+ std::vector<CTxOut>().swap(vout);
+ }
+
+ void swap(CCoins &to) {
+ std::swap(to.fCoinBase, fCoinBase);
+ to.vout.swap(vout);
+ std::swap(to.nHeight, nHeight);
+ std::swap(to.nVersion, nVersion);
+ }
+
+ // equality test
+ friend bool operator==(const CCoins &a, const CCoins &b) {
+ return a.fCoinBase == b.fCoinBase &&
+ a.nHeight == b.nHeight &&
+ a.nVersion == b.nVersion &&
+ a.vout == b.vout;
+ }
+ friend bool operator!=(const CCoins &a, const CCoins &b) {
+ return !(a == b);
+ }
+
+ // calculate number of bytes for the bitmask, and its number of non-zero bytes
+ // each bit in the bitmask represents the availability of one output, but the
+ // availabilities of the first two outputs are encoded separately
+ void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
+ unsigned int nLastUsedByte = 0;
+ for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
+ bool fZero = true;
+ for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
+ if (!vout[2+b*8+i].IsNull()) {
+ fZero = false;
+ continue;
+ }
+ }
+ if (!fZero) {
+ nLastUsedByte = b + 1;
+ nNonzeroBytes++;
+ }
+ }
+ nBytes += nLastUsedByte;
+ }
+
+ bool IsCoinBase() const {
+ return fCoinBase;
+ }
+
+ unsigned int GetSerializeSize(int nType, int nVersion) const {
+ unsigned int nSize = 0;
+ unsigned int nMaskSize = 0, nMaskCode = 0;
+ CalcMaskSize(nMaskSize, nMaskCode);
+ bool fFirst = vout.size() > 0 && !vout[0].IsNull();
+ bool fSecond = vout.size() > 1 && !vout[1].IsNull();
+ assert(fFirst || fSecond || nMaskCode);
+ unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+ // version
+ nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
+ // size of header code
+ nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
+ // spentness bitmask
+ nSize += nMaskSize;
+ // txouts themself
+ for (unsigned int i = 0; i < vout.size(); i++)
+ if (!vout[i].IsNull())
+ nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
+ // height
+ nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
+ return nSize;
+ }
+
+ template<typename Stream>
+ void Serialize(Stream &s, int nType, int nVersion) const {
+ unsigned int nMaskSize = 0, nMaskCode = 0;
+ CalcMaskSize(nMaskSize, nMaskCode);
+ bool fFirst = vout.size() > 0 && !vout[0].IsNull();
+ bool fSecond = vout.size() > 1 && !vout[1].IsNull();
+ assert(fFirst || fSecond || nMaskCode);
+ unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+ // version
+ ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
+ // header code
+ ::Serialize(s, VARINT(nCode), nType, nVersion);
+ // spentness bitmask
+ for (unsigned int b = 0; b<nMaskSize; b++) {
+ unsigned char chAvail = 0;
+ for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
+ if (!vout[2+b*8+i].IsNull())
+ chAvail |= (1 << i);
+ ::Serialize(s, chAvail, nType, nVersion);
+ }
+ // txouts themself
+ for (unsigned int i = 0; i < vout.size(); i++) {
+ if (!vout[i].IsNull())
+ ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
+ }
+ // coinbase height
+ ::Serialize(s, VARINT(nHeight), nType, nVersion);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream &s, int nType, int nVersion) {
+ unsigned int nCode = 0;
+ // version
+ ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
+ // header code
+ ::Unserialize(s, VARINT(nCode), nType, nVersion);
+ fCoinBase = nCode & 1;
+ std::vector<bool> vAvail(2, false);
+ vAvail[0] = nCode & 2;
+ vAvail[1] = nCode & 4;
+ unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
+ // spentness bitmask
+ while (nMaskCode > 0) {
+ unsigned char chAvail = 0;
+ ::Unserialize(s, chAvail, nType, nVersion);
+ for (unsigned int p = 0; p < 8; p++) {
+ bool f = (chAvail & (1 << p)) != 0;
+ vAvail.push_back(f);
+ }
+ if (chAvail != 0)
+ nMaskCode--;
+ }
+ // txouts themself
+ vout.assign(vAvail.size(), CTxOut());
+ for (unsigned int i = 0; i < vAvail.size(); i++) {
+ if (vAvail[i])
+ ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
+ }
+ // coinbase height
+ ::Unserialize(s, VARINT(nHeight), nType, nVersion);
+ Cleanup();
+ }
+
+ // mark an outpoint spent, and construct undo information
+ bool Spend(const COutPoint &out, CTxInUndo &undo) {
+ if (out.n >= vout.size())
+ return false;
+ if (vout[out.n].IsNull())
+ return false;
+ undo = CTxInUndo(vout[out.n]);
+ vout[out.n].SetNull();
+ Cleanup();
+ if (vout.size() == 0) {
+ undo.nHeight = nHeight;
+ undo.fCoinBase = fCoinBase;
+ undo.nVersion = this->nVersion;
+ }
+ return true;
+ }
+
+ // mark a vout spent
+ bool Spend(int nPos) {
+ CTxInUndo undo;
+ COutPoint out(0, nPos);
+ return Spend(out, undo);
+ }
+
+ // check whether a particular output is still available
+ bool IsAvailable(unsigned int nPos) const {
+ return (nPos < vout.size() && !vout[nPos].IsNull());
+ }
+
+ // check whether the entire CCoins is spent
+ // note that only !IsPruned() CCoins can be serialized
+ bool IsPruned() const {
+ BOOST_FOREACH(const CTxOut &out, vout)
+ if (!out.IsNull())
+ return false;
+ return true;
+ }
+};
+
+
+/** 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 int CURRENT_VERSION=2;
+ int nVersion;
+ uint256 hashPrevBlock;
+ uint256 hashMerkleRoot;
+ unsigned int nTime;
+ unsigned int nBits;
+ unsigned int nNonce;
+
+ CBlockHeader()
+ {
+ SetNull();
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ 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
+ {
+ return Hash(BEGIN(nVersion), END(nNonce));
+ }
+
+ int64 GetBlockTime() const
+ {
+ return (int64)nTime;
+ }
+};
+
+#endif
diff --git a/src/db.cpp b/src/db.cpp
index fd4c67d552..1f53917602 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -5,10 +5,12 @@
#include "db.h"
#include "util.h"
-#include "main.h"
+#include "hash.h"
+#include "addrman.h"
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <openssl/rand.h>
#ifndef WIN32
#include "sys/stat.h"
@@ -486,6 +488,7 @@ void CDBEnv::Flush(bool fShutdown)
// CAddrDB
//
+unsigned char CAddrDB::pchMessageStart[4] = { 0x00, 0x00, 0x00, 0x00 };
CAddrDB::CAddrDB()
{
@@ -501,7 +504,7 @@ bool CAddrDB::Write(const CAddrMan& addr)
// serialize addresses, checksum data up to that point, then append csum
CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
- ssPeers << FLATDATA(pchMessageStart);
+ ssPeers << FLATDATA(CAddrDB::pchMessageStart);
ssPeers << addr;
uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
ssPeers << hash;
@@ -566,11 +569,11 @@ bool CAddrDB::Read(CAddrMan& addr)
unsigned char pchMsgTmp[4];
try {
- // de-serialize file header (pchMessageStart magic number) and
+ // de-serialize file header (CAddrDB::pchMessageStart magic number) and
ssPeers >> FLATDATA(pchMsgTmp);
// verify the network matches ours
- if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp)))
+ if (memcmp(pchMsgTmp, CAddrDB::pchMessageStart, sizeof(pchMsgTmp)))
return error("CAddrman::Read() : invalid network magic number");
// de-serialize address data into one CAddrMan object
diff --git a/src/db.h b/src/db.h
index ea440c4960..92241f6cf2 100644
--- a/src/db.h
+++ b/src/db.h
@@ -5,22 +5,22 @@
#ifndef BITCOIN_DB_H
#define BITCOIN_DB_H
-#include "main.h"
+#include "sync.h"
+#include "serialize.h"
#include <map>
#include <string>
#include <vector>
+#include <boost/filesystem.hpp>
#include <db_cxx.h>
-class CAddress;
class CAddrMan;
class CBlockLocator;
class CDiskBlockIndex;
class CMasterKey;
class COutPoint;
class CWallet;
-class CWalletTx;
extern unsigned int nWalletDBUpdated;
@@ -318,10 +318,14 @@ class CAddrDB
{
private:
boost::filesystem::path pathAddr;
+ static unsigned char pchMessageStart[4];
+
public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
+
+ static void SetMessageStart(unsigned char _pchMessageStart[]) { memcpy(CAddrDB::pchMessageStart, _pchMessageStart, sizeof(CAddrDB::pchMessageStart)); }
};
#endif // BITCOIN_DB_H
diff --git a/src/init.cpp b/src/init.cpp
index dcc43d8368..f8b2b23fd0 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -3,11 +3,13 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "init.h"
+#include "main.h"
+#include "core.h"
#include "txdb.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
#include "net.h"
-#include "init.h"
#include "util.h"
#include "ui_interface.h"
#include "checkpoints.h"
@@ -45,6 +47,7 @@ enum BindFlags {
BF_REPORT_ERROR = (1U << 1)
};
+
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
@@ -99,6 +102,7 @@ void Shutdown()
StopRPCThreads();
ShutdownRPCMining();
bitdb.Flush(false);
+ GenerateBitcoins(false, NULL);
StopNode();
{
LOCK(cs_main);
@@ -567,6 +571,8 @@ bool AppInit2(boost::thread_group& threadGroup)
// ********************************************************* Step 6: network initialization
+ RegisterNodeSignals(GetNodeSignals());
+
int nSocksVersion = GetArg("-socks", 5);
if (nSocksVersion != 4 && nSocksVersion != 5)
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
@@ -928,6 +934,7 @@ bool AppInit2(boost::thread_group& threadGroup)
nStart = GetTimeMillis();
{
+ CAddrDB::SetMessageStart(pchMessageStart);
CAddrDB adb;
if (!adb.Read(addrman))
printf("Invalid or missing peers.dat; recreating\n");
diff --git a/src/main.cpp b/src/main.cpp
index b8b7771611..98921e1423 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -160,7 +160,22 @@ void static ResendWalletTransactions()
+//////////////////////////////////////////////////////////////////////////////
+//
+// Registration of network node signals.
+//
+
+void RegisterNodeSignals(CNodeSignals& nodeSignals)
+{
+ nodeSignals.ProcessMessages.connect(&ProcessMessages);
+ nodeSignals.SendMessages.connect(&SendMessages);
+}
+void UnregisterNodeSignals(CNodeSignals& nodeSignals)
+{
+ nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
+ nodeSignals.SendMessages.disconnect(&SendMessages);
+}
@@ -357,41 +372,23 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
-//////////////////////////////////////////////////////////////////////////////
-//
-// CTransaction / CTxOut
-//
-
-bool CTxOut::IsDust() const
-{
- // "Dust" is defined in terms of CTransaction::nMinRelayTxFee,
- // 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 33 bytes big, and will
- // need a CTxIn of at least 148 bytes to spend,
- // so dust is a txout less than 54 uBTC
- // (5430 satoshis) with default nMinRelayTxFee
- return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < CTransaction::nMinRelayTxFee);
-}
-
-bool CTransaction::IsStandard() const
+bool IsStandardTx(const CTransaction& tx)
{
- if (nVersion > CTransaction::CURRENT_VERSION)
+ if (tx.nVersion > CTransaction::CURRENT_VERSION)
return false;
- if (!IsFinal())
+ if (!IsFinalTx(tx))
return false;
// Extremely large transactions with lots of inputs can cost the network
// almost as much to process as they cost the sender in fees, because
// computing signature hashes is O(ninputs*txsize). Limiting transactions
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
- unsigned int sz = this->GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
+ unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
if (sz >= MAX_STANDARD_TX_SIZE)
return false;
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
@@ -401,15 +398,47 @@ bool CTransaction::IsStandard() const
if (!txin.scriptSig.IsPushOnly())
return false;
}
- BOOST_FOREACH(const CTxOut& txout, vout) {
+ BOOST_FOREACH(const CTxOut& txout, tx.vout) {
if (!::IsStandard(txout.scriptPubKey))
return false;
- if (txout.IsDust())
+ if (txout.IsDust(CTransaction::nMinRelayTxFee))
return false;
}
return true;
}
+bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64 nBlockTime)
+{
+ // Time based nLockTime implemented in 0.1.6
+ if (tx.nLockTime == 0)
+ return true;
+ if (nBlockHeight == 0)
+ nBlockHeight = nBestHeight;
+ if (nBlockTime == 0)
+ nBlockTime = GetAdjustedTime();
+ if ((int64)tx.nLockTime < ((int64)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
+ return true;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ if (!txin.IsFinal())
+ return false;
+ return true;
+}
+
+/** Amount of bitcoins spent by the transaction.
+ @return sum of all outputs (note: does not include fees)
+ */
+int64 GetValueOut(const CTransaction& tx)
+{
+ int64 nValueOut = 0;
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ {
+ nValueOut += txout.nValue;
+ if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
+ throw std::runtime_error("GetValueOut() : value out of range");
+ }
+ return nValueOut;
+}
+
//
// Check transaction inputs, and make sure any
// pay-to-script-hash transactions are evaluating IsStandard scripts
@@ -421,14 +450,14 @@ bool CTransaction::IsStandard() const
// expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
-bool CTransaction::AreInputsStandard(CCoinsViewCache& mapInputs) const
+bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
{
- if (IsCoinBase())
+ if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
- for (unsigned int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
+ const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
@@ -446,7 +475,7 @@ bool CTransaction::AreInputsStandard(CCoinsViewCache& mapInputs) const
// beside "push data" in the scriptSig the
// IsStandard() call returns false
vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, vin[i].scriptSig, *this, i, false, 0))
+ if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false, 0))
return false;
if (whichType == TX_SCRIPTHASH)
@@ -475,20 +504,34 @@ bool CTransaction::AreInputsStandard(CCoinsViewCache& mapInputs) const
return true;
}
-unsigned int CTransaction::GetLegacySigOpCount() const
+unsigned int GetLegacySigOpCount(const CTransaction& tx)
{
unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
nSigOps += txin.scriptSig.GetSigOpCount(false);
}
- BOOST_FOREACH(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
}
return nSigOps;
}
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs)
+{
+ if (tx.IsCoinBase())
+ return 0;
+
+ unsigned int nSigOps = 0;
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]);
+ if (prevout.scriptPubKey.IsPayToScriptHash())
+ nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
+ }
+ return nSigOps;
+}
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
{
@@ -543,25 +586,25 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
-bool CTransaction::CheckTransaction(CValidationState &state) const
+bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{
// Basic checks that don't depend on any context
- if (vin.empty())
- return state.DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
- if (vout.empty())
- return state.DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
+ if (tx.vin.empty())
+ return state.DoS(10, error("CheckTransaction() : vin empty"));
+ if (tx.vout.empty())
+ return state.DoS(10, error("CheckTransaction() : vout empty"));
// Size limits
- if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
+ if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
int64 nValueOut = 0;
- BOOST_FOREACH(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
if (txout.nValue < 0)
- return state.DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
+ return state.DoS(100, error("CheckTransaction() : txout.nValue negative"));
if (txout.nValue > MAX_MONEY)
- return state.DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
+ return state.DoS(100, error("CheckTransaction() : txout.nValue too high"));
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
@@ -569,35 +612,34 @@ bool CTransaction::CheckTransaction(CValidationState &state) const
// Check for duplicate inputs
set<COutPoint> vInOutPoints;
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (vInOutPoints.count(txin.prevout))
return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs"));
vInOutPoints.insert(txin.prevout);
}
- if (IsCoinBase())
+ if (tx.IsCoinBase())
{
- if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return state.DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
+ if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
+ return state.DoS(100, error("CheckTransaction() : coinbase script size"));
}
else
{
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull())
- return state.DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
+ return state.DoS(10, error("CheckTransaction() : prevout is null"));
}
return true;
}
-int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
- enum GetMinFee_mode mode) const
+int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize, bool fAllowFree, enum GetMinFee_mode mode)
{
// Base fee is either nMinTxFee or nMinRelayTxFee
- int64 nBaseFee = (mode == GMF_RELAY) ? nMinRelayTxFee : nMinTxFee;
+ int64 nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee;
- unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+ unsigned int nBytes = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
unsigned int nNewBlockSize = nBlockSize + nBytes;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
@@ -621,7 +663,7 @@ int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
// To limit dust spam, require base fee if any output is less than 0.01
if (nMinFee < nBaseFee)
{
- BOOST_FOREACH(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
if (txout.nValue < CENT)
nMinFee = nBaseFee;
}
@@ -658,7 +700,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
if (pfMissingInputs)
*pfMissingInputs = false;
- if (!tx.CheckTransaction(state))
+ if (!CheckTransaction(tx, state))
return error("CTxMemPool::accept() : CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction
@@ -670,7 +712,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet)
- if (!fTestNet && !tx.IsStandard())
+ if (!fTestNet && !IsStandardTx(tx))
return error("CTxMemPool::accept() : nonstandard transaction type");
// is it already in the memory pool?
@@ -695,7 +737,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
if (i != 0)
return false;
ptxOld = mapNextTx[outpoint].ptx;
- if (ptxOld->IsFinal())
+ if (IsFinalTx(*ptxOld))
return false;
if (!tx.IsNewerThan(*ptxOld))
return false;
@@ -735,7 +777,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
}
// are the actual inputs available?
- if (!tx.HaveInputs(view))
+ if (!view.HaveInputs(tx))
return state.Invalid(error("CTxMemPool::accept() : inputs already spent"));
// Bring the best block into scope
@@ -746,18 +788,18 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
}
// Check for non-standard pay-to-script-hash in inputs
- if (!tx.AreInputsStandard(view) && !fTestNet)
+ if (!AreInputsStandard(tx, view) && !fTestNet)
return error("CTxMemPool::accept() : nonstandard transaction input");
// Note: if you modify this code to accept non-standard transactions, then
// you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications.
- int64 nFees = tx.GetValueIn(view)-tx.GetValueOut();
+ int64 nFees = view.GetValueIn(tx)-GetValueOut(tx);
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Don't accept it if it can't get into a block
- int64 txMinFee = tx.GetMinFee(1000, true, GMF_RELAY);
+ int64 txMinFee = GetMinFee(tx, 1000, true, GMF_RELAY);
if (fLimitFree && nFees < txMinFee)
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
hash.ToString().c_str(),
@@ -788,7 +830,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC))
+ if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC))
{
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().c_str());
}
@@ -817,14 +859,6 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
return true;
}
-bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs)
-{
- try {
- return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs);
- } catch(std::runtime_error &e) {
- return state.Abort(_("System error: ") + e.what());
- }
-}
bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
{
@@ -937,7 +971,7 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree)
{
CValidationState state;
- return CTransaction::AcceptToMemoryPool(state, fCheckInputs, fLimitFree);
+ return mempool.accept(state, *this, fCheckInputs, fLimitFree, NULL);
}
@@ -1281,13 +1315,13 @@ bool ConnectBestBlock(CValidationState &state) {
} while(true);
}
-void CBlockHeader::UpdateTime(const CBlockIndex* pindexPrev)
+void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
{
- nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
// Updating time can change work required on testnet:
if (fTestNet)
- nBits = GetNextWorkRequired(pindexPrev, this);
+ block.nBits = GetNextWorkRequired(pindexPrev, &block);
}
@@ -1300,45 +1334,30 @@ void CBlockHeader::UpdateTime(const CBlockIndex* pindexPrev)
-const CTxOut &CTransaction::GetOutputFor(const CTxIn& input, CCoinsViewCache& view)
+const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input)
{
- const CCoins &coins = view.GetCoins(input.prevout.hash);
+ const CCoins &coins = GetCoins(input.prevout.hash);
assert(coins.IsAvailable(input.prevout.n));
return coins.vout[input.prevout.n];
}
-int64 CTransaction::GetValueIn(CCoinsViewCache& inputs) const
+int64 CCoinsViewCache::GetValueIn(const CTransaction& tx)
{
- if (IsCoinBase())
+ if (tx.IsCoinBase())
return 0;
int64 nResult = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- nResult += GetOutputFor(vin[i], inputs).nValue;
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ nResult += GetOutputFor(tx.vin[i]).nValue;
return nResult;
}
-unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const
-{
- if (IsCoinBase())
- return 0;
-
- unsigned int nSigOps = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- const CTxOut &prevout = GetOutputFor(vin[i], inputs);
- if (prevout.scriptPubKey.IsPayToScriptHash())
- nSigOps += prevout.scriptPubKey.GetSigOpCount(vin[i].scriptSig);
- }
- return nSigOps;
-}
-
-void CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const
+void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash)
{
// mark inputs spent
- if (!IsCoinBase()) {
- BOOST_FOREACH(const CTxIn &txin, vin) {
+ if (!tx.IsCoinBase()) {
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
CCoins &coins = inputs.GetCoins(txin.prevout.hash);
CTxInUndo undo;
assert(coins.Spend(txin.prevout, undo));
@@ -1347,23 +1366,23 @@ void CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs,
}
// add outputs
- assert(inputs.SetCoins(txhash, CCoins(*this, nHeight)));
+ assert(inputs.SetCoins(txhash, CCoins(tx, nHeight)));
}
-bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const
+bool CCoinsViewCache::HaveInputs(const CTransaction& tx)
{
- if (!IsCoinBase()) {
+ if (!tx.IsCoinBase()) {
// first check whether information about the prevout hash is available
- for (unsigned int i = 0; i < vin.size(); i++) {
- const COutPoint &prevout = vin[i].prevout;
- if (!inputs.HaveCoins(prevout.hash))
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ const COutPoint &prevout = tx.vin[i].prevout;
+ if (!HaveCoins(prevout.hash))
return false;
}
// then check whether the actual outputs are available
- for (unsigned int i = 0; i < vin.size(); i++) {
- const COutPoint &prevout = vin[i].prevout;
- const CCoins &coins = inputs.GetCoins(prevout.hash);
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ const COutPoint &prevout = tx.vin[i].prevout;
+ const CCoins &coins = GetCoins(prevout.hash);
if (!coins.IsAvailable(prevout.n))
return false;
}
@@ -1383,26 +1402,26 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
}
-bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks) const
+bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
{
- if (!IsCoinBase())
+ if (!tx.IsCoinBase())
{
if (pvChecks)
- pvChecks->reserve(vin.size());
+ pvChecks->reserve(tx.vin.size());
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
- if (!HaveInputs(inputs))
- return state.Invalid(error("CheckInputs() : %s inputs unavailable", GetHash().ToString().c_str()));
+ if (!inputs.HaveInputs(tx))
+ return state.Invalid(error("CheckInputs() : %s inputs unavailable", tx.GetHash().ToString().c_str()));
// While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks.
int nSpendHeight = inputs.GetBestBlock()->nHeight + 1;
int64 nValueIn = 0;
int64 nFees = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- const COutPoint &prevout = vin[i].prevout;
+ const COutPoint &prevout = tx.vin[i].prevout;
const CCoins &coins = inputs.GetCoins(prevout.hash);
// If prev is coinbase, check that it's matured
@@ -1418,13 +1437,13 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs,
}
- if (nValueIn < GetValueOut())
- return state.DoS(100, error("CheckInputs() : %s value in < value out", GetHash().ToString().c_str()));
+ if (nValueIn < GetValueOut(tx))
+ return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString().c_str()));
// Tally transaction fees
- int64 nTxFee = nValueIn - GetValueOut();
+ int64 nTxFee = nValueIn - GetValueOut(tx);
if (nTxFee < 0)
- return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", GetHash().ToString().c_str()));
+ return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString().c_str()));
nFees += nTxFee;
if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs() : nFees out of range"));
@@ -1437,12 +1456,12 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs,
// before the last block chain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
if (fScriptChecks) {
- for (unsigned int i = 0; i < vin.size(); i++) {
- const COutPoint &prevout = vin[i].prevout;
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ const COutPoint &prevout = tx.vin[i].prevout;
const CCoins &coins = inputs.GetCoins(prevout.hash);
// Verify signature
- CScriptCheck check(coins, *this, i, flags, 0);
+ CScriptCheck check(coins, tx, i, flags, 0);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1450,7 +1469,7 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs,
if (flags & SCRIPT_VERIFY_STRICTENC) {
// For now, check whether the failure was caused by non-canonical
// encodings or not; if so, don't trigger DoS protection.
- CScriptCheck check(coins, *this, i, flags & (~SCRIPT_VERIFY_STRICTENC), 0);
+ CScriptCheck check(coins, tx, i, flags & (~SCRIPT_VERIFY_STRICTENC), 0);
if (check())
return state.Invalid();
}
@@ -1465,7 +1484,6 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs,
-
bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
{
assert(pindex == view.GetBestBlock());
@@ -1645,13 +1663,13 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
const CTransaction &tx = vtx[i];
nInputs += tx.vin.size();
- nSigOps += tx.GetLegacySigOpCount();
+ nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many sigops"));
if (!tx.IsCoinBase())
{
- if (!tx.HaveInputs(view))
+ if (!view.HaveInputs(tx))
return state.DoS(100, error("ConnectBlock() : inputs missing/spent"));
if (fStrictPayToScriptHash)
@@ -1659,21 +1677,21 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
- nSigOps += tx.GetP2SHSigOpCount(view);
+ nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many sigops"));
}
- nFees += tx.GetValueIn(view)-tx.GetValueOut();
+ nFees += view.GetValueIn(tx)-GetValueOut(tx);
std::vector<CScriptCheck> vChecks;
- if (!tx.CheckInputs(state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
CTxUndo txundo;
- tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i));
+ UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i));
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
@@ -1684,8 +1702,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
if (fBenchmark)
printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
- if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
- return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)));
+ if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
+ return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
if (!control.Wait())
return state.DoS(100, false);
@@ -1847,7 +1865,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
BOOST_FOREACH(CTransaction& tx, vResurrect) {
// ignore validation errors in resurrected transactions
CValidationState stateDummy;
- tx.AcceptToMemoryPool(stateDummy, true, false);
+ mempool.accept(stateDummy, tx, true, false, NULL);
}
// Delete redundant memory transactions that are in the connected branch
@@ -2077,7 +2095,7 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)
- if (!tx.CheckTransaction(state))
+ if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
// Build the merkle tree already. We need it anyway later, and it makes the
@@ -2097,7 +2115,7 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
- nSigOps += tx.GetLegacySigOpCount();
+ nSigOps += GetLegacySigOpCount(tx);
}
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
@@ -2136,7 +2154,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
- if (!tx.IsFinal(nHeight, GetBlockTime()))
+ if (!IsFinalTx(tx, nHeight, GetBlockTime()))
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"));
// Check that the block chain matches the known block chain up to a checkpoint
@@ -2208,6 +2226,17 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
+void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
+{
+ // Filter out duplicate requests
+ if (pindexBegin == pnode->pindexLastGetBlocksBegin && hashEnd == pnode->hashLastGetBlocksEnd)
+ return;
+ pnode->pindexLastGetBlocksBegin = pindexBegin;
+ pnode->hashLastGetBlocksEnd = hashEnd;
+
+ pnode->PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
+}
+
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
// Check for duplicate
@@ -2253,7 +2282,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
// Ask this guy to fill in what we're missing
- pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
+ PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(pblock2));
}
return true;
}
@@ -3357,12 +3386,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!fImporting && !fReindex)
pfrom->AskFor(inv);
} else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
- pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+ PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
} else if (nInv == nLastBlock) {
// In case we are on a very long side-chain, it is possible that we already have
// the last block in an inv bundle sent in response to getblocks. Try to detect
// this situation and push another getblocks to continue.
- pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
+ PushGetBlocks(pfrom, mapBlockIndex[inv.hash], uint256(0));
if (fDebug)
printf("force request: %s\n", inv.ToString().c_str());
}
@@ -3478,7 +3507,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool fMissingInputs = false;
CValidationState state;
- if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
+ if (mempool.accept(state, tx, true, true, &fMissingInputs))
{
RelayTransaction(tx, inv.hash, vMsg);
mapAlreadyAskedFor.erase(inv);
@@ -3501,7 +3530,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get anyone relaying LegitTxX banned)
CValidationState stateDummy;
- if (tx.AcceptToMemoryPool(stateDummy, true, true, &fMissingInputs2))
+ if (mempool.accept(stateDummy, tx, true, true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().c_str());
RelayTransaction(tx, inv.hash, vMsg);
@@ -3839,7 +3868,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// Start block sync
if (pto->fStartSync && !fImporting && !fReindex) {
pto->fStartSync = false;
- pto->PushGetBlocks(pindexBest, uint256(0));
+ PushGetBlocks(pto, pindexBest, uint256(0));
}
// Resend wallet transactions that haven't gotten in a block yet
@@ -4184,7 +4213,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
{
CTransaction& tx = (*mi).second;
- if (tx.IsCoinBase() || !tx.IsFinal())
+ if (tx.IsCoinBase() || !IsFinalTx(tx))
continue;
COrphan* porphan = NULL;
@@ -4239,7 +4268,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// This is a more accurate fee-per-kilobyte than is used by the client code, because the
// client code rounds up the size to the nearest 1K. That's good, because it gives an
// incentive to create smaller transactions.
- double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0);
+ double dFeePerKb = double(nTotalIn-GetValueOut(tx)) / (double(nTxSize)/1000.0);
if (porphan)
{
@@ -4275,7 +4304,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
continue;
// Legacy limits on sigOps:
- unsigned int nTxSigOps = tx.GetLegacySigOpCount();
+ unsigned int nTxSigOps = GetLegacySigOpCount(tx);
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
@@ -4293,22 +4322,22 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
}
- if (!tx.HaveInputs(view))
+ if (!view.HaveInputs(tx))
continue;
- int64 nTxFees = tx.GetValueIn(view)-tx.GetValueOut();
+ int64 nTxFees = view.GetValueIn(tx)-GetValueOut(tx);
- nTxSigOps += tx.GetP2SHSigOpCount(view);
+ nTxSigOps += GetP2SHSigOpCount(tx, view);
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
CValidationState state;
- if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH))
+ if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH))
continue;
CTxUndo txundo;
uint256 hash = tx.GetHash();
- tx.UpdateCoins(state, view, txundo, pindexPrev->nHeight+1, hash);
+ UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
// Added
pblock->vtx.push_back(tx);
@@ -4352,11 +4381,11 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
- pblock->UpdateTime(pindexPrev);
+ UpdateTime(*pblock, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
pblock->nNonce = 0;
pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
- pblocktemplate->vTxSigOps[0] = pblock->vtx[0].GetLegacySigOpCount();
+ pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
CBlockIndex indexDummy(*pblock);
indexDummy.pprev = pindexPrev;
@@ -4592,7 +4621,7 @@ void static BitcoinMiner(CWallet *pwallet)
break;
// Update nTime every few seconds
- pblock->UpdateTime(pindexPrev);
+ UpdateTime(*pblock, pindexPrev);
nBlockTime = ByteReverse(pblock->nTime);
if (fTestNet)
{
diff --git a/src/main.h b/src/main.h
index fae37ea512..f20fad98a4 100644
--- a/src/main.h
+++ b/src/main.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H
+#include "core.h"
#include "bignum.h"
#include "sync.h"
#include "net.h"
@@ -34,8 +35,6 @@ static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5;
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
-/** The maximum number of entries in an 'inv' protocol message */
-static const unsigned int MAX_INV_SZ = 50000;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
@@ -122,6 +121,14 @@ void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
/** Push an updated transaction to all registered wallets */
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
+
+/** Register with a network node to receive its signals */
+void RegisterNodeSignals(CNodeSignals& nodeSignals);
+/** Unregister a network node */
+void UnregisterNodeSignals(CNodeSignals& nodeSignals);
+
+void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
+
/** Process an incoming block */
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
@@ -176,6 +183,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
/** Find the best known block, and make it the tip of the block chain */
bool ConnectBestBlock(CValidationState &state);
+
+void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev);
+
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
/** Verify a signature */
@@ -249,210 +259,6 @@ struct CDiskTxPos : public CDiskBlockPos
};
-/** An inpoint - a combination of a transaction and an index n into its vin */
-class CInPoint
-{
-public:
- CTransaction* ptx;
- unsigned int n;
-
- CInPoint() { SetNull(); }
- CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
- void SetNull() { ptx = NULL; n = (unsigned int) -1; }
- bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
-};
-
-
-
-/** An outpoint - a combination of a transaction hash and an index n into its vout */
-class COutPoint
-{
-public:
- uint256 hash;
- unsigned int n;
-
- COutPoint() { SetNull(); }
- COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
- IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
- void SetNull() { hash = 0; n = (unsigned int) -1; }
- bool IsNull() const { return (hash == 0 && n == (unsigned int) -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
- {
- return strprintf("COutPoint(%s, %u)", hash.ToString().c_str(), n);
- }
-
- void print() const
- {
- printf("%s\n", ToString().c_str());
- }
-};
-
-
-
-
-/** 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;
- unsigned int nSequence;
-
- CTxIn()
- {
- nSequence = std::numeric_limits<unsigned int>::max();
- }
-
- explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
- {
- prevout = prevoutIn;
- scriptSig = scriptSigIn;
- nSequence = nSequenceIn;
- }
-
- CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
- {
- prevout = COutPoint(hashPrevTx, nOut);
- scriptSig = scriptSigIn;
- nSequence = nSequenceIn;
- }
-
- IMPLEMENT_SERIALIZE
- (
- READWRITE(prevout);
- READWRITE(scriptSig);
- READWRITE(nSequence);
- )
-
- bool IsFinal() const
- {
- return (nSequence == std::numeric_limits<unsigned int>::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
- {
- std::string str;
- str += "CTxIn(";
- str += prevout.ToString();
- if (prevout.IsNull())
- str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
- else
- str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
- if (nSequence != std::numeric_limits<unsigned int>::max())
- str += strprintf(", nSequence=%u", nSequence);
- str += ")";
- return str;
- }
-
- void print() const
- {
- printf("%s\n", ToString().c_str());
- }
-};
-
-
-
-
-/** 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:
- int64 nValue;
- CScript scriptPubKey;
-
- CTxOut()
- {
- SetNull();
- }
-
- CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
- {
- nValue = nValueIn;
- scriptPubKey = scriptPubKeyIn;
- }
-
- IMPLEMENT_SERIALIZE
- (
- READWRITE(nValue);
- READWRITE(scriptPubKey);
- )
-
- void SetNull()
- {
- nValue = -1;
- scriptPubKey.clear();
- }
-
- bool IsNull() const
- {
- return (nValue == -1);
- }
-
- uint256 GetHash() const
- {
- return SerializeHash(*this);
- }
-
- 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);
- }
-
- bool IsDust() const;
-
- std::string ToString() const
- {
- if (scriptPubKey.size() < 6)
- return "CTxOut(error)";
- return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
- }
-
- void print() const
- {
- printf("%s\n", ToString().c_str());
- }
-};
-
-
enum GetMinFee_mode
{
@@ -461,298 +267,72 @@ enum GetMinFee_mode
GMF_SEND,
};
-/** The basic transaction that is broadcasted on the network and contained in
- * blocks. A transaction can contain multiple inputs and outputs.
- */
-class CTransaction
-{
-public:
- static int64 nMinTxFee;
- static int64 nMinRelayTxFee;
- static const int CURRENT_VERSION=1;
- int nVersion;
- std::vector<CTxIn> vin;
- std::vector<CTxOut> vout;
- unsigned int nLockTime;
-
- CTransaction()
- {
- SetNull();
- }
-
- IMPLEMENT_SERIALIZE
- (
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(vin);
- READWRITE(vout);
- READWRITE(nLockTime);
- )
-
- void SetNull()
- {
- nVersion = CTransaction::CURRENT_VERSION;
- vin.clear();
- vout.clear();
- nLockTime = 0;
- }
-
- bool IsNull() const
- {
- return (vin.empty() && vout.empty());
- }
-
- uint256 GetHash() const
- {
- return SerializeHash(*this);
- }
-
- bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
- {
- // Time based nLockTime implemented in 0.1.6
- if (nLockTime == 0)
- return true;
- if (nBlockHeight == 0)
- nBlockHeight = nBestHeight;
- if (nBlockTime == 0)
- nBlockTime = GetAdjustedTime();
- if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
- return true;
- BOOST_FOREACH(const CTxIn& txin, vin)
- if (!txin.IsFinal())
- return false;
- return true;
- }
-
- bool IsNewerThan(const CTransaction& old) const
- {
- if (vin.size() != old.vin.size())
- return false;
- for (unsigned int i = 0; i < vin.size(); i++)
- if (vin[i].prevout != old.vin[i].prevout)
- return false;
-
- bool fNewer = false;
- unsigned int nLowest = std::numeric_limits<unsigned int>::max();
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- if (vin[i].nSequence != old.vin[i].nSequence)
- {
- if (vin[i].nSequence <= nLowest)
- {
- fNewer = false;
- nLowest = vin[i].nSequence;
- }
- if (old.vin[i].nSequence < nLowest)
- {
- fNewer = true;
- nLowest = old.vin[i].nSequence;
- }
- }
- }
- return fNewer;
- }
-
- bool IsCoinBase() const
- {
- return (vin.size() == 1 && vin[0].prevout.IsNull());
- }
+int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, bool fAllowFree = true, enum GetMinFee_mode mode = GMF_BLOCK);
- /** Check for standard transaction types
- @return True if all outputs (scriptPubKeys) use only standard transaction forms
- */
- bool IsStandard() const;
+//
+// Check transaction inputs, and make sure any
+// pay-to-script-hash transactions are evaluating IsStandard scripts
+//
+// Why bother? To avoid denial-of-service attacks; an attacker
+// can submit a standard HASH... OP_EQUAL transaction,
+// which will get accepted into blocks. The redemption
+// script can be anything; an attacker could use a very
+// expensive-to-check-upon-redemption script like:
+// DUP CHECKSIG DROP ... repeated 100 times... OP_1
+//
/** Check for standard transaction types
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ @param[in] mapInputs Map of previous transactions that have outputs we're spending
@return True if all inputs (scriptSigs) use only standard transaction forms
*/
- bool AreInputsStandard(CCoinsViewCache& mapInputs) const;
+bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs);
- /** Count ECDSA signature operations the old-fashioned (pre-0.6) way
- @return number of sigops this transaction's outputs will produce when spent
- */
- unsigned int GetLegacySigOpCount() const;
+/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
+ @return number of sigops this transaction's outputs will produce when spent
+ @see CTransaction::FetchInputs
+*/
+unsigned int GetLegacySigOpCount(const CTransaction& tx);
- /** Count ECDSA signature operations in pay-to-script-hash inputs.
+/** Count ECDSA signature operations in pay-to-script-hash inputs.
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
- @return maximum number of sigops required to validate this transaction's inputs
- */
- unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const;
-
- /** Amount of bitcoins spent by this transaction.
- @return sum of all outputs (note: does not include fees)
- */
- int64 GetValueOut() const
- {
- int64 nValueOut = 0;
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- nValueOut += txout.nValue;
- if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
- }
- return nValueOut;
- }
-
- /** Amount of bitcoins coming in to this transaction
- Note that lightweight clients may not know anything besides the hash of previous transactions,
- so may not be able to calculate this.
-
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
- @return Sum of value of all inputs (scriptSigs)
- */
- int64 GetValueIn(CCoinsViewCache& mapInputs) const;
-
- static bool AllowFree(double dPriority)
- {
- // Large (in bytes) low-priority (new, small-coin) transactions
- // need a fee.
- return dPriority > COIN * 144 / 250;
- }
-
- int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const;
-
- friend bool operator==(const CTransaction& a, const CTransaction& b)
- {
- return (a.nVersion == b.nVersion &&
- a.vin == b.vin &&
- a.vout == b.vout &&
- a.nLockTime == b.nLockTime);
- }
-
- friend bool operator!=(const CTransaction& a, const CTransaction& b)
- {
- return !(a == b);
- }
-
-
- std::string ToString() const
- {
- std::string str;
- str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n",
- GetHash().ToString().c_str(),
- 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;
- }
-
- void print() const
- {
- printf("%s", ToString().c_str());
- }
-
-
- // Check whether all prevouts of this transaction are present in the UTXO set represented by view
- bool HaveInputs(CCoinsViewCache &view) const;
-
- // Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
- // This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
- // instead of being performed inline.
- bool CheckInputs(CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
- unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
- std::vector<CScriptCheck> *pvChecks = NULL) const;
-
- // Apply the effects of this transaction on the UTXO set represented by view
- void UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
-
- // Context-independent validity checks
- bool CheckTransaction(CValidationState &state) const;
-
- // Try to accept this transaction into the memory pool
- bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL);
+ @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ @return maximum number of sigops required to validate this transaction's inputs
+ @see CTransaction::FetchInputs
+ */
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs);
-protected:
- static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
-};
-/** wrapper for CTxOut that provides a more compact serialization */
-class CTxOutCompressor
+inline bool AllowFree(double dPriority)
{
-private:
- CTxOut &txout;
+ // Large (in bytes) low-priority (new, small-coin) transactions
+ // need a fee.
+ return dPriority > COIN * 144 / 250;
+}
-public:
- static uint64 CompressAmount(uint64 nAmount);
- static uint64 DecompressAmount(uint64 nAmount);
+// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
+// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
+// instead of being performed inline.
+bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
+ unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
+ std::vector<CScriptCheck> *pvChecks = NULL);
- CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
+// Apply the effects of this transaction on the UTXO set represented by view
+bool UpdateCoins(const CTransaction& tx, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash);
- IMPLEMENT_SERIALIZE(({
- if (!fRead) {
- uint64 nVal = CompressAmount(txout.nValue);
- READWRITE(VARINT(nVal));
- } else {
- uint64 nVal = 0;
- READWRITE(VARINT(nVal));
- txout.nValue = DecompressAmount(nVal);
- }
- CScriptCompressor cscript(REF(txout.scriptPubKey));
- READWRITE(cscript);
- });)
-};
+// Context-independent validity checks
+bool CheckTransaction(const CTransaction& tx, CValidationState& state);
-/** 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);
- }
-};
+/** Check for standard transaction types
+ @return True if all outputs (scriptPubKeys) use only standard transaction forms
+*/
+bool IsStandardTx(const CTransaction& tx);
-/** Undo information for a CTransaction */
-class CTxUndo
-{
-public:
- // undo information for all txins
- std::vector<CTxInUndo> vprevout;
+bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0);
- IMPLEMENT_SERIALIZE(
- READWRITE(vprevout);
- )
-};
+/** Amount of bitcoins spent by the transaction.
+ @return sum of all outputs (note: does not include fees)
+ */
+int64 GetValueOut(const CTransaction& tx);
/** Undo information for a CBlock */
class CBlockUndo
@@ -824,254 +404,6 @@ public:
}
};
-/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
- *
- * Serialized format:
- * - VARINT(nVersion)
- * - VARINT(nCode)
- * - unspentness bitvector, for vout[2] and further; least significant byte first
- * - the non-spent CTxOuts (via CTxOutCompressor)
- * - VARINT(nHeight)
- *
- * The nCode value consists of:
- * - bit 1: IsCoinBase()
- * - bit 2: vout[0] is not spent
- * - bit 4: vout[1] is not spent
- * - The higher bits encode N, the number of non-zero bytes in the following bitvector.
- * - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at
- * least one non-spent output).
- *
- * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e
- * <><><--------------------------------------------><---->
- * | \ | /
- * version code vout[1] height
- *
- * - version = 1
- * - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
- * - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
- * - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
- * * 8358: compact amount representation for 60000000000 (600 BTC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
- * - height = 203998
- *
- *
- * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b
- * <><><--><--------------------------------------------------><----------------------------------------------><---->
- * / \ \ | | /
- * version code unspentness vout[4] vout[16] height
- *
- * - version = 1
- * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
- * 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
- * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
- * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
- * * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
- * - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
- * * bbd123: compact amount representation for 110397 (0.001 BTC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
- * - height = 120891
- */
-class CCoins
-{
-public:
- // whether transaction is a coinbase
- bool fCoinBase;
-
- // unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
- std::vector<CTxOut> vout;
-
- // at which height this transaction was included in the active block chain
- int nHeight;
-
- // version of the CTransaction; accesses to this value should probably check for nHeight as well,
- // as new tx version will probably only be introduced at certain heights
- int nVersion;
-
- // construct a CCoins from a CTransaction, at a given height
- CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) { }
-
- // empty constructor
- CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { }
-
- // remove spent outputs at the end of vout
- void Cleanup() {
- while (vout.size() > 0 && vout.back().IsNull())
- vout.pop_back();
- if (vout.empty())
- std::vector<CTxOut>().swap(vout);
- }
-
- void swap(CCoins &to) {
- std::swap(to.fCoinBase, fCoinBase);
- to.vout.swap(vout);
- std::swap(to.nHeight, nHeight);
- std::swap(to.nVersion, nVersion);
- }
-
- // equality test
- friend bool operator==(const CCoins &a, const CCoins &b) {
- return a.fCoinBase == b.fCoinBase &&
- a.nHeight == b.nHeight &&
- a.nVersion == b.nVersion &&
- a.vout == b.vout;
- }
- friend bool operator!=(const CCoins &a, const CCoins &b) {
- return !(a == b);
- }
-
- // calculate number of bytes for the bitmask, and its number of non-zero bytes
- // each bit in the bitmask represents the availability of one output, but the
- // availabilities of the first two outputs are encoded separately
- void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
- unsigned int nLastUsedByte = 0;
- for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
- bool fZero = true;
- for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
- if (!vout[2+b*8+i].IsNull()) {
- fZero = false;
- continue;
- }
- }
- if (!fZero) {
- nLastUsedByte = b + 1;
- nNonzeroBytes++;
- }
- }
- nBytes += nLastUsedByte;
- }
-
- bool IsCoinBase() const {
- return fCoinBase;
- }
-
- unsigned int GetSerializeSize(int nType, int nVersion) const {
- unsigned int nSize = 0;
- unsigned int nMaskSize = 0, nMaskCode = 0;
- CalcMaskSize(nMaskSize, nMaskCode);
- bool fFirst = vout.size() > 0 && !vout[0].IsNull();
- bool fSecond = vout.size() > 1 && !vout[1].IsNull();
- assert(fFirst || fSecond || nMaskCode);
- unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
- // version
- nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
- // size of header code
- nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
- // spentness bitmask
- nSize += nMaskSize;
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++)
- if (!vout[i].IsNull())
- nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
- // height
- nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
- return nSize;
- }
-
- template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersion) const {
- unsigned int nMaskSize = 0, nMaskCode = 0;
- CalcMaskSize(nMaskSize, nMaskCode);
- bool fFirst = vout.size() > 0 && !vout[0].IsNull();
- bool fSecond = vout.size() > 1 && !vout[1].IsNull();
- assert(fFirst || fSecond || nMaskCode);
- unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
- // version
- ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
- // header code
- ::Serialize(s, VARINT(nCode), nType, nVersion);
- // spentness bitmask
- for (unsigned int b = 0; b<nMaskSize; b++) {
- unsigned char chAvail = 0;
- for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
- if (!vout[2+b*8+i].IsNull())
- chAvail |= (1 << i);
- ::Serialize(s, chAvail, nType, nVersion);
- }
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++) {
- if (!vout[i].IsNull())
- ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
- }
- // coinbase height
- ::Serialize(s, VARINT(nHeight), nType, nVersion);
- }
-
- template<typename Stream>
- void Unserialize(Stream &s, int nType, int nVersion) {
- unsigned int nCode = 0;
- // version
- ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
- // header code
- ::Unserialize(s, VARINT(nCode), nType, nVersion);
- fCoinBase = nCode & 1;
- std::vector<bool> vAvail(2, false);
- vAvail[0] = nCode & 2;
- vAvail[1] = nCode & 4;
- unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
- // spentness bitmask
- while (nMaskCode > 0) {
- unsigned char chAvail = 0;
- ::Unserialize(s, chAvail, nType, nVersion);
- for (unsigned int p = 0; p < 8; p++) {
- bool f = (chAvail & (1 << p)) != 0;
- vAvail.push_back(f);
- }
- if (chAvail != 0)
- nMaskCode--;
- }
- // txouts themself
- vout.assign(vAvail.size(), CTxOut());
- for (unsigned int i = 0; i < vAvail.size(); i++) {
- if (vAvail[i])
- ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
- }
- // coinbase height
- ::Unserialize(s, VARINT(nHeight), nType, nVersion);
- Cleanup();
- }
-
- // mark an outpoint spent, and construct undo information
- bool Spend(const COutPoint &out, CTxInUndo &undo) {
- if (out.n >= vout.size())
- return false;
- if (vout[out.n].IsNull())
- return false;
- undo = CTxInUndo(vout[out.n]);
- vout[out.n].SetNull();
- Cleanup();
- if (vout.size() == 0) {
- undo.nHeight = nHeight;
- undo.fCoinBase = fCoinBase;
- undo.nVersion = this->nVersion;
- }
- return true;
- }
-
- // mark a vout spent
- bool Spend(int nPos) {
- CTxInUndo undo;
- COutPoint out(0, nPos);
- return Spend(out, undo);
- }
-
- // check whether a particular output is still available
- bool IsAvailable(unsigned int nPos) const {
- return (nPos < vout.size() && !vout[nPos].IsNull());
- }
-
- // check whether the entire CCoins is spent
- // note that only !IsPruned() CCoins can be serialized
- bool IsPruned() const {
- BOOST_FOREACH(const CTxOut &out, vout)
- if (!out.IsNull())
- return false;
- return true;
- }
-};
/** Closure representing one script verification
* Note that this stores references to the spending transaction */
@@ -1250,69 +582,6 @@ public:
};
-/** 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 int CURRENT_VERSION=2;
- int nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- unsigned int nTime;
- unsigned int nBits;
- unsigned int nNonce;
-
- CBlockHeader()
- {
- SetNull();
- }
-
- IMPLEMENT_SERIALIZE
- (
- 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
- {
- return Hash(BEGIN(nVersion), END(nNonce));
- }
-
- int64 GetBlockTime() const
- {
- return (int64)nTime;
- }
-
- void UpdateTime(const CBlockIndex* pindexPrev);
-};
-
class CBlock : public CBlockHeader
{
public:
@@ -2183,6 +1452,21 @@ public:
// Calculate the size of the cache (in number of transactions)
unsigned int GetCacheSize();
+ /** Amount of bitcoins coming in to a transaction
+ Note that lightweight clients may not know anything besides the hash of previous transactions,
+ so may not be able to calculate this.
+
+ @param[in] tx transaction for which we are checking input total
+ @return Sum of value of all inputs (scriptSigs)
+ @see CTransaction::FetchInputs
+ */
+ int64 GetValueIn(const CTransaction& tx);
+
+ // Check whether all prevouts of the transaction are present in the UTXO set represented by this view
+ bool HaveInputs(const CTransaction& tx);
+
+ const CTxOut &GetOutputFor(const CTxIn& input);
+
private:
std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid);
};
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 114a9491bd..9cfab5942a 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -73,6 +73,7 @@ OBJS= \
obj/init.o \
obj/bitcoind.o \
obj/keystore.o \
+ obj/core.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 34ddc3eece..33cc7e6b4a 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -81,6 +81,7 @@ OBJS= \
obj/init.o \
obj/bitcoind.o \
obj/keystore.o \
+ obj/core.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
diff --git a/src/makefile.osx b/src/makefile.osx
index 4ee0edcb95..bef0ef3518 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -84,6 +84,7 @@ OBJS= \
obj/init.o \
obj/bitcoind.o \
obj/keystore.o \
+ obj/core.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
diff --git a/src/makefile.unix b/src/makefile.unix
index f8042b2930..a83bab1047 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -123,6 +123,7 @@ OBJS= \
obj/init.o \
obj/bitcoind.o \
obj/keystore.o \
+ obj/core.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
diff --git a/src/net.cpp b/src/net.cpp
index 54ed1d9b51..adc5f93029 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -5,7 +5,7 @@
#include "db.h"
#include "net.h"
-#include "init.h"
+#include "core.h"
#include "addrman.h"
#include "ui_interface.h"
#include "script.h"
@@ -68,6 +68,10 @@ CCriticalSection cs_vAddedNodes;
static CSemaphore *semOutbound = NULL;
+// Signals for message handling
+static CNodeSignals g_signals;
+CNodeSignals& GetNodeSignals() { return g_signals; }
+
void AddOneShot(string strDest)
{
LOCK(cs_vOneShots);
@@ -79,17 +83,6 @@ unsigned short GetListenPort()
return (unsigned short)(GetArg("-port", GetDefaultPort()));
}
-void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
-{
- // Filter out duplicate requests
- if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
- return;
- pindexLastGetBlocksBegin = pindexBegin;
- hashLastGetBlocksEnd = hashEnd;
-
- PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
-}
-
// find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{
@@ -1574,11 +1567,6 @@ void static StartSync(const vector<CNode*> &vNodes) {
CNode *pnodeNewSync = NULL;
double dBestScore = 0;
- // fImporting and fReindex are accessed out of cs_main here, but only
- // as an optimization - they are checked again in SendMessages.
- if (fImporting || fReindex)
- return;
-
// Iterate over all nodes
BOOST_FOREACH(CNode* pnode, vNodes) {
// check preconditions for allowing a sync
@@ -1635,7 +1623,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv)
- if (!ProcessMessages(pnode))
+ if (!g_signals.ProcessMessages(pnode))
pnode->CloseSocketDisconnect();
}
boost::this_thread::interruption_point();
@@ -1644,7 +1632,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- SendMessages(pnode, pnode == pnodeTrickle);
+ g_signals.SendMessages(pnode, pnode == pnodeTrickle);
}
boost::this_thread::interruption_point();
}
@@ -1861,9 +1849,7 @@ void StartNode(boost::thread_group& threadGroup)
bool StopNode()
{
printf("StopNode()\n");
- GenerateBitcoins(false, NULL);
MapPort(false);
- nTransactionsUpdated++;
if (semOutbound)
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
semOutbound->post();
diff --git a/src/net.h b/src/net.h
index af66eed070..e75fe48f64 100644
--- a/src/net.h
+++ b/src/net.h
@@ -8,6 +8,7 @@
#include <deque>
#include <boost/array.hpp>
#include <boost/foreach.hpp>
+#include <boost/signals2/signal.hpp>
#include <openssl/rand.h>
#ifndef WIN32
@@ -22,6 +23,9 @@
#include "hash.h"
#include "bloom.h"
+/** The maximum number of entries in an 'inv' protocol message */
+static const unsigned int MAX_INV_SZ = 50000;
+
class CNode;
class CBlockIndex;
extern int nBestHeight;
@@ -45,6 +49,16 @@ void StartNode(boost::thread_group& threadGroup);
bool StopNode();
void SocketSendData(CNode *pnode);
+// Signals for message handling
+struct CNodeSignals
+{
+ boost::signals2::signal<bool (CNode*)> ProcessMessages;
+ boost::signals2::signal<bool (CNode*, bool)> SendMessages;
+};
+
+CNodeSignals& GetNodeSignals();
+
+
enum
{
LOCAL_NONE, // unknown
@@ -600,7 +614,6 @@ public:
}
}
- void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 88bbe49afd..1e22467a33 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -6,7 +6,6 @@
#include "protocol.h"
#include "util.h"
#include "netbase.h"
-#include "main.h"
#ifndef WIN32
# include <arpa/inet.h>
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index e4dbf9c0d9..aeef721ce5 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -12,7 +12,7 @@
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
- if (!wtx.IsFinal())
+ if (!IsFinalTx(wtx))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight + 1);
@@ -186,7 +186,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
}
- int64 nTxFee = nDebit - wtx.GetValueOut();
+ int64 nTxFee = nDebit - GetValueOut(wtx);
if (nTxFee > 0)
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 40a5f735cd..e954508769 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -89,7 +89,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
//
// Debit
//
- int64 nTxFee = nDebit - wtx.GetValueOut();
+ int64 nTxFee = nDebit - GetValueOut(wtx);
for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
{
@@ -162,7 +162,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = nBestHeight;
- if (!wtx.IsFinal())
+ if (!IsFinalTx(wtx))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
{
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index d2cac68706..6f8ac7a112 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -159,7 +159,7 @@ Value getwork(const Array& params, bool fHelp)
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime
- pblock->UpdateTime(pindexPrev);
+ UpdateTime(*pblock, pindexPrev);
pblock->nNonce = 0;
// Update nExtraNonce
@@ -289,7 +289,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime
- pblock->UpdateTime(pindexPrev);
+ UpdateTime(*pblock, pindexPrev);
pblock->nNonce = 0;
Array transactions;
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index c1e05466e5..917c2f5de9 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -555,7 +555,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
if (!fHave) {
// push to local node
CValidationState state;
- if (!tx.AcceptToMemoryPool(state, true, false))
+ if (!mempool.accept(state, tx, true, false, NULL))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
}
}
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index fbad1944de..585bdb2bfb 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -408,7 +408,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !wtx.IsFinal())
+ if (wtx.IsCoinBase() || !IsFinalTx(wtx))
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
@@ -454,7 +454,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !wtx.IsFinal())
+ if (wtx.IsCoinBase() || !IsFinalTx(wtx))
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
@@ -478,7 +478,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (!wtx.IsFinal())
+ if (!IsFinalTx(wtx))
continue;
int64 nReceived, nSent, nFee;
@@ -839,7 +839,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !wtx.IsFinal())
+ if (wtx.IsCoinBase() || !IsFinalTx(wtx))
continue;
int nDepth = wtx.GetDepthInMainChain();
@@ -1220,7 +1220,7 @@ Value gettransaction(const Array& params, bool fHelp)
int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
- int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+ int64 nFee = (wtx.IsFromMe() ? GetValueOut(wtx) - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe())
diff --git a/src/script.cpp b/src/script.cpp
index b411666353..cf6eeaf392 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -9,10 +9,10 @@ using namespace std;
using namespace boost;
#include "script.h"
+#include "core.h"
#include "keystore.h"
#include "bignum.h"
#include "key.h"
-#include "main.h"
#include "sync.h"
#include "util.h"
diff --git a/src/script.h b/src/script.h
index 3cbb2cf322..f963467c94 100644
--- a/src/script.h
+++ b/src/script.h
@@ -533,7 +533,7 @@ public:
bool IsPayToScriptHash() const;
- // Called by CTransaction::IsStandard
+ // Called by IsStandardTx
bool IsPushOnly() const
{
const_iterator pc = begin();
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index 81e77b7df8..a26f4a87db 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -23,7 +23,7 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true],
-["Tests for CTransaction::CheckTransaction()"],
+["Tests for CheckTransaction()"],
["No inputs"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
"0100000000010000000000000000015100000000", true],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 8aeb30f35b..faf911a97f 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -50,7 +50,7 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true],
-["Tests for CTransaction::CheckTransaction()"],
+["Tests for CheckTransaction()"],
["MAX_MONEY output"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true],
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 65f0ad0cdc..23cb3a8e0a 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(sign)
txFrom.vout[i+4].scriptPubKey = standardScripts[i];
txFrom.vout[i+4].nValue = COIN;
}
- BOOST_CHECK(txFrom.IsStandard());
+ BOOST_CHECK(IsStandardTx(txFrom));
CTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++)
@@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(set)
txFrom.vout[i].scriptPubKey = outer[i];
txFrom.vout[i].nValue = CENT;
}
- BOOST_CHECK(txFrom.IsStandard());
+ BOOST_CHECK(IsStandardTx(txFrom));
CTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++)
@@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(set)
for (int i = 0; i < 4; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
- BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i));
+ BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i]), strprintf("txTo[%d].IsStandard", i));
}
}
@@ -305,15 +305,15 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[2].prevout.hash = txFrom.GetHash();
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
- BOOST_CHECK(txTo.AreInputsStandard(coins));
- BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(coins), 1U);
+ BOOST_CHECK(::AreInputsStandard(txTo, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 1U);
// Make sure adding crap to the scriptSigs makes them non-standard:
for (int i = 0; i < 3; i++)
{
CScript t = txTo.vin[i].scriptSig;
txTo.vin[i].scriptSig = (CScript() << 11) + t;
- BOOST_CHECK(!txTo.AreInputsStandard(coins));
+ BOOST_CHECK(!::AreInputsStandard(txTo, coins));
txTo.vin[i].scriptSig = t;
}
@@ -329,11 +329,11 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
- BOOST_CHECK(!txToNonStd.AreInputsStandard(coins));
- BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(coins), 11U);
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd, coins), 11U);
txToNonStd.vin[0].scriptSig.clear();
- BOOST_CHECK(!txToNonStd.AreInputsStandard(coins));
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index ddff2acd4e..53d1307b69 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx;
CValidationState state;
- BOOST_CHECK_MESSAGE(tx.CheckTransaction(state), strTest);
+ BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
stream >> tx;
CValidationState state;
- fValid = tx.CheckTransaction(state) && state.IsValid();
+ fValid = CheckTransaction(tx, state) && state.IsValid();
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
@@ -163,11 +163,11 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CTransaction tx;
stream >> tx;
CValidationState state;
- BOOST_CHECK_MESSAGE(tx.CheckTransaction(state) && state.IsValid(), "Simple deserialized transaction should be valid.");
+ BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
// Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]);
- BOOST_CHECK_MESSAGE(!tx.CheckTransaction(state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
+ BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
}
//
@@ -230,16 +230,16 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1;
- BOOST_CHECK(t1.AreInputsStandard(coins));
- BOOST_CHECK_EQUAL(t1.GetValueIn(coins), (50+21+22)*CENT);
+ BOOST_CHECK(AreInputsStandard(t1, coins));
+ BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
// Adding extra junk to the scriptSig should make it non-standard:
t1.vin[0].scriptSig << OP_11;
- BOOST_CHECK(!t1.AreInputsStandard(coins));
+ BOOST_CHECK(!AreInputsStandard(t1, coins));
// ... as should not having enough:
t1.vin[0].scriptSig = CScript();
- BOOST_CHECK(!t1.AreInputsStandard(coins));
+ BOOST_CHECK(!AreInputsStandard(t1, coins));
}
BOOST_AUTO_TEST_CASE(test_IsStandard)
@@ -260,16 +260,16 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
key.MakeNewKey(true);
t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
- BOOST_CHECK(t.IsStandard());
+ BOOST_CHECK(IsStandardTx(t));
t.vout[0].nValue = 5011; // dust
- BOOST_CHECK(!t.IsStandard());
+ BOOST_CHECK(!IsStandardTx(t));
t.vout[0].nValue = 6011; // not dust
- BOOST_CHECK(t.IsStandard());
+ BOOST_CHECK(IsStandardTx(t));
t.vout[0].scriptPubKey = CScript() << OP_1;
- BOOST_CHECK(!t.IsStandard());
+ BOOST_CHECK(!IsStandardTx(t));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 549d9bbf4b..7041d49dab 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -643,7 +643,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived,
int64 nDebit = GetDebit();
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- int64 nValueOut = GetValueOut();
+ int64 nValueOut = GetValueOut(*this);
nFee = nDebit - nValueOut;
}
@@ -933,7 +933,7 @@ int64 CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -965,7 +965,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
{
const CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal())
+ if (!IsFinalTx(*pcoin))
continue;
if (fOnlyConfirmed && !pcoin->IsConfirmed())
@@ -1178,7 +1178,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
{
CTxOut txout(s.second, s.first);
- if (txout.IsDust())
+ if (txout.IsDust(CTransaction::nMinRelayTxFee))
{
strFailReason = _("Transaction amount too small");
return false;
@@ -1237,7 +1237,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust())
+ if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
{
nFeeRet += nChange;
reservekey.ReturnKey();
@@ -1276,8 +1276,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
// Check that enough fee is included
int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
- bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
+ bool fAllowFree = AllowFree(dPriority);
+ int64 nMinFee = GetMinFee(wtxNew, 1, fAllowFree, GMF_SEND);
if (nFeeRet < max(nPayFee, nMinFee))
{
nFeeRet = max(nPayFee, nMinFee);
@@ -1657,7 +1657,7 @@ std::map<CTxDestination, int64> CWallet::GetAddressBalances()
{
CWalletTx *pcoin = &walletEntry.second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
diff --git a/src/wallet.h b/src/wallet.h
index 7fcb8e13ce..674bae66dd 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H
+#include "walletdb.h"
+
#include <string>
#include <vector>
@@ -16,12 +18,12 @@
#include "script.h"
#include "ui_interface.h"
#include "util.h"
-#include "walletdb.h"
class CAccountingEntry;
class CWalletTx;
class CReserveKey;
class COutput;
+class CWalletDB;
/** (client) version numbers for particular wallet features */
enum WalletFeature
@@ -639,7 +641,7 @@ public:
bool IsConfirmed() const
{
// Quick answer in most cases
- if (!IsFinal())
+ if (!IsFinalTx(*this))
return false;
if (GetDepthInMainChain() >= 1)
return true;
@@ -656,7 +658,7 @@ public:
{
const CMerkleTx* ptx = vWorkQueue[i];
- if (!ptx->IsFinal())
+ if (!IsFinalTx(*ptx))
return false;
if (ptx->GetDepthInMainChain() >= 1)
continue;
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 4a73413d26..8910cac4bc 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -204,7 +204,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx;
CValidationState state;
- if (wtx.CheckTransaction(state) && (wtx.GetHash() == hash) && state.IsValid())
+ if (CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid())
wtx.BindWallet(pwallet);
else
{
diff --git a/src/walletdb.h b/src/walletdb.h
index 8ae6c3ff49..9732eb29e4 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -11,6 +11,8 @@
class CKeyPool;
class CAccount;
class CAccountingEntry;
+class CWallet;
+class CWalletTx;
/** Error statuses for the wallet database */
enum DBErrors
@@ -160,4 +162,6 @@ public:
static bool Recover(CDBEnv& dbenv, std::string filename);
};
+bool BackupWallet(const CWallet& wallet, const std::string& strDest);
+
#endif // BITCOIN_WALLETDB_H