Browse Source

Merge pull request #2154 from CodeShark/dependencycleanup

Clean up code dependencies
0.10
Jeff Garzik 12 years ago
parent
commit
f59530ce6e
  1. 2
      bitcoin-qt.pro
  2. 7
      src/core.cpp
  3. 736
      src/core.h
  4. 11
      src/db.cpp
  5. 10
      src/db.h
  6. 9
      src/init.cpp
  7. 331
      src/main.cpp
  8. 850
      src/main.h
  9. 1
      src/makefile.linux-mingw
  10. 1
      src/makefile.mingw
  11. 1
      src/makefile.osx
  12. 1
      src/makefile.unix
  13. 28
      src/net.cpp
  14. 15
      src/net.h
  15. 1
      src/protocol.cpp
  16. 4
      src/qt/transactiondesc.cpp
  17. 4
      src/qt/transactionrecord.cpp
  18. 4
      src/rpcmining.cpp
  19. 2
      src/rpcrawtransaction.cpp
  20. 10
      src/rpcwallet.cpp
  21. 2
      src/script.cpp
  22. 2
      src/script.h
  23. 2
      src/test/data/tx_invalid.json
  24. 2
      src/test/data/tx_valid.json
  25. 18
      src/test/script_P2SH_tests.cpp
  26. 24
      src/test/transaction_tests.cpp
  27. 16
      src/wallet.cpp
  28. 8
      src/wallet.h
  29. 2
      src/walletdb.cpp
  30. 4
      src/walletdb.h

2
bitcoin-qt.pro

@ -154,6 +154,7 @@ HEADERS += src/qt/bitcoingui.h \
src/hash.h \ src/hash.h \
src/uint256.h \ src/uint256.h \
src/serialize.h \ src/serialize.h \
src/core.h \
src/main.h \ src/main.h \
src/net.h \ src/net.h \
src/key.h \ src/key.h \
@ -233,6 +234,7 @@ SOURCES += src/qt/bitcoin.cpp \
src/netbase.cpp \ src/netbase.cpp \
src/key.cpp \ src/key.cpp \
src/script.cpp \ src/script.cpp \
src/core.cpp \
src/main.cpp \ src/main.cpp \
src/init.cpp \ src/init.cpp \
src/net.cpp \ src/net.cpp \

7
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"

736
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

11
src/db.cpp

@ -5,10 +5,12 @@
#include "db.h" #include "db.h"
#include "util.h" #include "util.h"
#include "main.h" #include "hash.h"
#include "addrman.h"
#include <boost/version.hpp> #include <boost/version.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <openssl/rand.h>
#ifndef WIN32 #ifndef WIN32
#include "sys/stat.h" #include "sys/stat.h"
@ -486,6 +488,7 @@ void CDBEnv::Flush(bool fShutdown)
// CAddrDB // CAddrDB
// //
unsigned char CAddrDB::pchMessageStart[4] = { 0x00, 0x00, 0x00, 0x00 };
CAddrDB::CAddrDB() CAddrDB::CAddrDB()
{ {
@ -501,7 +504,7 @@ bool CAddrDB::Write(const CAddrMan& addr)
// serialize addresses, checksum data up to that point, then append csum // serialize addresses, checksum data up to that point, then append csum
CDataStream ssPeers(SER_DISK, CLIENT_VERSION); CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
ssPeers << FLATDATA(pchMessageStart); ssPeers << FLATDATA(CAddrDB::pchMessageStart);
ssPeers << addr; ssPeers << addr;
uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
ssPeers << hash; ssPeers << hash;
@ -566,11 +569,11 @@ bool CAddrDB::Read(CAddrMan& addr)
unsigned char pchMsgTmp[4]; unsigned char pchMsgTmp[4];
try { try {
// de-serialize file header (pchMessageStart magic number) and // de-serialize file header (CAddrDB::pchMessageStart magic number) and
ssPeers >> FLATDATA(pchMsgTmp); ssPeers >> FLATDATA(pchMsgTmp);
// verify the network matches ours // 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"); return error("CAddrman::Read() : invalid network magic number");
// de-serialize address data into one CAddrMan object // de-serialize address data into one CAddrMan object

10
src/db.h

@ -5,22 +5,22 @@
#ifndef BITCOIN_DB_H #ifndef BITCOIN_DB_H
#define BITCOIN_DB_H #define BITCOIN_DB_H
#include "main.h" #include "sync.h"
#include "serialize.h"
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/filesystem.hpp>
#include <db_cxx.h> #include <db_cxx.h>
class CAddress;
class CAddrMan; class CAddrMan;
class CBlockLocator; class CBlockLocator;
class CDiskBlockIndex; class CDiskBlockIndex;
class CMasterKey; class CMasterKey;
class COutPoint; class COutPoint;
class CWallet; class CWallet;
class CWalletTx;
extern unsigned int nWalletDBUpdated; extern unsigned int nWalletDBUpdated;
@ -318,10 +318,14 @@ class CAddrDB
{ {
private: private:
boost::filesystem::path pathAddr; boost::filesystem::path pathAddr;
static unsigned char pchMessageStart[4];
public: public:
CAddrDB(); CAddrDB();
bool Write(const CAddrMan& addr); bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr); bool Read(CAddrMan& addr);
static void SetMessageStart(unsigned char _pchMessageStart[]) { memcpy(CAddrDB::pchMessageStart, _pchMessageStart, sizeof(CAddrDB::pchMessageStart)); }
}; };
#endif // BITCOIN_DB_H #endif // BITCOIN_DB_H

9
src/init.cpp

@ -3,11 +3,13 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "init.h"
#include "main.h"
#include "core.h"
#include "txdb.h" #include "txdb.h"
#include "walletdb.h" #include "walletdb.h"
#include "bitcoinrpc.h" #include "bitcoinrpc.h"
#include "net.h" #include "net.h"
#include "init.h"
#include "util.h" #include "util.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "checkpoints.h" #include "checkpoints.h"
@ -45,6 +47,7 @@ enum BindFlags {
BF_REPORT_ERROR = (1U << 1) BF_REPORT_ERROR = (1U << 1)
}; };
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Shutdown // Shutdown
@ -99,6 +102,7 @@ void Shutdown()
StopRPCThreads(); StopRPCThreads();
ShutdownRPCMining(); ShutdownRPCMining();
bitdb.Flush(false); bitdb.Flush(false);
GenerateBitcoins(false, NULL);
StopNode(); StopNode();
{ {
LOCK(cs_main); LOCK(cs_main);
@ -567,6 +571,8 @@ bool AppInit2(boost::thread_group& threadGroup)
// ********************************************************* Step 6: network initialization // ********************************************************* Step 6: network initialization
RegisterNodeSignals(GetNodeSignals());
int nSocksVersion = GetArg("-socks", 5); int nSocksVersion = GetArg("-socks", 5);
if (nSocksVersion != 4 && nSocksVersion != 5) if (nSocksVersion != 4 && nSocksVersion != 5)
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion)); return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
@ -928,6 +934,7 @@ bool AppInit2(boost::thread_group& threadGroup)
nStart = GetTimeMillis(); nStart = GetTimeMillis();
{ {
CAddrDB::SetMessageStart(pchMessageStart);
CAddrDB adb; CAddrDB adb;
if (!adb.Read(addrman)) if (!adb.Read(addrman))
printf("Invalid or missing peers.dat; recreating\n"); printf("Invalid or missing peers.dat; recreating\n");

331
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)
////////////////////////////////////////////////////////////////////////////// bool IsStandardTx(const CTransaction& tx)
//
// 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
{ {
if (nVersion > CTransaction::CURRENT_VERSION) if (tx.nVersion > CTransaction::CURRENT_VERSION)
return false; return false;
if (!IsFinal()) if (!IsFinalTx(tx))
return false; return false;
// Extremely large transactions with lots of inputs can cost the network // Extremely large transactions with lots of inputs can cost the network
// almost as much to process as they cost the sender in fees, because // almost as much to process as they cost the sender in fees, because
// computing signature hashes is O(ninputs*txsize). Limiting transactions // computing signature hashes is O(ninputs*txsize). Limiting transactions
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. // 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) if (sz >= MAX_STANDARD_TX_SIZE)
return false; 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 // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// pay-to-script-hash, which is 3 ~80-byte signatures, 3 // pay-to-script-hash, which is 3 ~80-byte signatures, 3
@ -401,15 +398,47 @@ bool CTransaction::IsStandard() const
if (!txin.scriptSig.IsPushOnly()) if (!txin.scriptSig.IsPushOnly())
return false; return false;
} }
BOOST_FOREACH(const CTxOut& txout, vout) { BOOST_FOREACH(const CTxOut& txout, tx.vout) {
if (!::IsStandard(txout.scriptPubKey)) if (!::IsStandard(txout.scriptPubKey))
return false; return false;
if (txout.IsDust()) if (txout.IsDust(CTransaction::nMinRelayTxFee))
return false; return false;
} }
return true; 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 // Check transaction inputs, and make sure any
// pay-to-script-hash transactions are evaluating IsStandard scripts // pay-to-script-hash transactions are evaluating IsStandard scripts
@ -421,14 +450,14 @@ bool CTransaction::IsStandard() const
// expensive-to-check-upon-redemption script like: // expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1 // 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 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; vector<vector<unsigned char> > vSolutions;
txnouttype whichType; txnouttype whichType;
@ -446,7 +475,7 @@ bool CTransaction::AreInputsStandard(CCoinsViewCache& mapInputs) const
// beside "push data" in the scriptSig the // beside "push data" in the scriptSig the
// IsStandard() call returns false // IsStandard() call returns false
vector<vector<unsigned char> > stack; 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; return false;
if (whichType == TX_SCRIPTHASH) if (whichType == TX_SCRIPTHASH)
@ -475,20 +504,34 @@ bool CTransaction::AreInputsStandard(CCoinsViewCache& mapInputs) const
return true; return true;
} }
unsigned int CTransaction::GetLegacySigOpCount() const unsigned int GetLegacySigOpCount(const CTransaction& tx)
{ {
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
BOOST_FOREACH(const CTxIn& txin, vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
{ {
nSigOps += txin.scriptSig.GetSigOpCount(false); nSigOps += txin.scriptSig.GetSigOpCount(false);
} }
BOOST_FOREACH(const CTxOut& txout, vout) BOOST_FOREACH(const CTxOut& txout, tx.vout)
{ {
nSigOps += txout.scriptPubKey.GetSigOpCount(false); nSigOps += txout.scriptPubKey.GetSigOpCount(false);
} }
return nSigOps; 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) 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 // Basic checks that don't depend on any context
if (vin.empty()) if (tx.vin.empty())
return state.DoS(10, error("CTransaction::CheckTransaction() : vin empty")); return state.DoS(10, error("CheckTransaction() : vin empty"));
if (vout.empty()) if (tx.vout.empty())
return state.DoS(10, error("CTransaction::CheckTransaction() : vout empty")); return state.DoS(10, error("CheckTransaction() : vout empty"));
// Size limits // 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")); return state.DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values // Check for negative or overflow output values
int64 nValueOut = 0; int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout) BOOST_FOREACH(const CTxOut& txout, tx.vout)
{ {
if (txout.nValue < 0) 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) 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; nValueOut += txout.nValue;
if (!MoneyRange(nValueOut)) if (!MoneyRange(nValueOut))
return state.DoS(100, error("CTransaction::CheckTransaction() : txout total out of range")); 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 // Check for duplicate inputs
set<COutPoint> vInOutPoints; set<COutPoint> vInOutPoints;
BOOST_FOREACH(const CTxIn& txin, vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
{ {
if (vInOutPoints.count(txin.prevout)) if (vInOutPoints.count(txin.prevout))
return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs")); return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs"));
vInOutPoints.insert(txin.prevout); vInOutPoints.insert(txin.prevout);
} }
if (IsCoinBase()) if (tx.IsCoinBase())
{ {
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100) if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, error("CTransaction::CheckTransaction() : coinbase script size")); return state.DoS(100, error("CheckTransaction() : coinbase script size"));
} }
else else
{ {
BOOST_FOREACH(const CTxIn& txin, vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull()) 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; return true;
} }
int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize, bool fAllowFree, enum GetMinFee_mode mode)
enum GetMinFee_mode mode) const
{ {
// Base fee is either nMinTxFee or nMinRelayTxFee // 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; unsigned int nNewBlockSize = nBlockSize + nBytes;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; 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 // To limit dust spam, require base fee if any output is less than 0.01
if (nMinFee < nBaseFee) if (nMinFee < nBaseFee)
{ {
BOOST_FOREACH(const CTxOut& txout, vout) BOOST_FOREACH(const CTxOut& txout, tx.vout)
if (txout.nValue < CENT) if (txout.nValue < CENT)
nMinFee = nBaseFee; nMinFee = nBaseFee;
} }
@ -658,7 +700,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
if (pfMissingInputs) if (pfMissingInputs)
*pfMissingInputs = false; *pfMissingInputs = false;
if (!tx.CheckTransaction(state)) if (!CheckTransaction(tx, state))
return error("CTxMemPool::accept() : CheckTransaction failed"); return error("CTxMemPool::accept() : CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction // 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"); return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet) // Rather not work on nonstandard transactions (unless -testnet)
if (!fTestNet && !tx.IsStandard()) if (!fTestNet && !IsStandardTx(tx))
return error("CTxMemPool::accept() : nonstandard transaction type"); return error("CTxMemPool::accept() : nonstandard transaction type");
// is it already in the memory pool? // is it already in the memory pool?
@ -695,7 +737,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
if (i != 0) if (i != 0)
return false; return false;
ptxOld = mapNextTx[outpoint].ptx; ptxOld = mapNextTx[outpoint].ptx;
if (ptxOld->IsFinal()) if (IsFinalTx(*ptxOld))
return false; return false;
if (!tx.IsNewerThan(*ptxOld)) if (!tx.IsNewerThan(*ptxOld))
return false; return false;
@ -735,7 +777,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
} }
// are the actual inputs available? // are the actual inputs available?
if (!tx.HaveInputs(view)) if (!view.HaveInputs(tx))
return state.Invalid(error("CTxMemPool::accept() : inputs already spent")); return state.Invalid(error("CTxMemPool::accept() : inputs already spent"));
// Bring the best block into scope // 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 // 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"); return error("CTxMemPool::accept() : nonstandard transaction input");
// Note: if you modify this code to accept non-standard transactions, then // Note: if you modify this code to accept non-standard transactions, then
// you should add code here to check that the transaction does a // you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications. // 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); unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Don't accept it if it can't get into a block // 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) if (fLimitFree && nFees < txMinFee)
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d, return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
hash.ToString().c_str(), hash.ToString().c_str(),
@ -788,7 +830,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
// Check against previous transactions // Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks. // 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()); 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; 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) bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
{ {
@ -937,7 +971,7 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree) bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree)
{ {
CValidationState state; 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); } 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: // Updating time can change work required on testnet:
if (fTestNet) 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)); assert(coins.IsAvailable(input.prevout.n));
return coins.vout[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; return 0;
int64 nResult = 0; int64 nResult = 0;
for (unsigned int i = 0; i < vin.size(); i++) for (unsigned int i = 0; i < tx.vin.size(); i++)
nResult += GetOutputFor(vin[i], inputs).nValue; nResult += GetOutputFor(tx.vin[i]).nValue;
return nResult; return nResult;
} }
unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash)
{
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
{ {
// mark inputs spent // mark inputs spent
if (!IsCoinBase()) { if (!tx.IsCoinBase()) {
BOOST_FOREACH(const CTxIn &txin, vin) { BOOST_FOREACH(const CTxIn &txin, tx.vin) {
CCoins &coins = inputs.GetCoins(txin.prevout.hash); CCoins &coins = inputs.GetCoins(txin.prevout.hash);
CTxInUndo undo; CTxInUndo undo;
assert(coins.Spend(txin.prevout, undo)); assert(coins.Spend(txin.prevout, undo));
@ -1347,23 +1366,23 @@ void CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs,
} }
// add outputs // 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 // first check whether information about the prevout hash is available
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;
if (!inputs.HaveCoins(prevout.hash)) if (!HaveCoins(prevout.hash))
return false; return false;
} }
// then check whether the actual outputs are available // then check whether the actual outputs are available
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); const CCoins &coins = GetCoins(prevout.hash);
if (!coins.IsAvailable(prevout.n)) if (!coins.IsAvailable(prevout.n))
return false; return false;
} }
@ -1383,26 +1402,26 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)(); 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) 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 // 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. // for an attacker to attempt to split the network.
if (!HaveInputs(inputs)) if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs() : %s inputs unavailable", GetHash().ToString().c_str())); return state.Invalid(error("CheckInputs() : %s inputs unavailable", tx.GetHash().ToString().c_str()));
// While checking, GetBestBlock() refers to the parent block. // While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks. // This is also true for mempool checks.
int nSpendHeight = inputs.GetBestBlock()->nHeight + 1; int nSpendHeight = inputs.GetBestBlock()->nHeight + 1;
int64 nValueIn = 0; int64 nValueIn = 0;
int64 nFees = 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); const CCoins &coins = inputs.GetCoins(prevout.hash);
// If prev is coinbase, check that it's matured // If prev is coinbase, check that it's matured
@ -1418,13 +1437,13 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs,
} }
if (nValueIn < GetValueOut()) if (nValueIn < GetValueOut(tx))
return state.DoS(100, error("CheckInputs() : %s value in < value out", GetHash().ToString().c_str())); return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString().c_str()));
// Tally transaction fees // Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut(); int64 nTxFee = nValueIn - GetValueOut(tx);
if (nTxFee < 0) 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; nFees += nTxFee;
if (!MoneyRange(nFees)) if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs() : nFees out of range")); 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 // 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. // still computed and checked, and any change will be caught at the next checkpoint.
if (fScriptChecks) { if (fScriptChecks) {
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); const CCoins &coins = inputs.GetCoins(prevout.hash);
// Verify signature // Verify signature
CScriptCheck check(coins, *this, i, flags, 0); CScriptCheck check(coins, tx, i, flags, 0);
if (pvChecks) { if (pvChecks) {
pvChecks->push_back(CScriptCheck()); pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back()); check.swap(pvChecks->back());
@ -1450,7 +1469,7 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs,
if (flags & SCRIPT_VERIFY_STRICTENC) { if (flags & SCRIPT_VERIFY_STRICTENC) {
// For now, check whether the failure was caused by non-canonical // For now, check whether the failure was caused by non-canonical
// encodings or not; if so, don't trigger DoS protection. // 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()) if (check())
return state.Invalid(); 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) bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
{ {
assert(pindex == view.GetBestBlock()); assert(pindex == view.GetBestBlock());
@ -1645,13 +1663,13 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
const CTransaction &tx = vtx[i]; const CTransaction &tx = vtx[i];
nInputs += tx.vin.size(); nInputs += tx.vin.size();
nSigOps += tx.GetLegacySigOpCount(); nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many sigops")); return state.DoS(100, error("ConnectBlock() : too many sigops"));
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
{ {
if (!tx.HaveInputs(view)) if (!view.HaveInputs(tx))
return state.DoS(100, error("ConnectBlock() : inputs missing/spent")); return state.DoS(100, error("ConnectBlock() : inputs missing/spent"));
if (fStrictPayToScriptHash) if (fStrictPayToScriptHash)
@ -1659,21 +1677,21 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
// Add in sigops done by pay-to-script-hash inputs; // Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating // this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block. // an incredibly-expensive-to-validate block.
nSigOps += tx.GetP2SHSigOpCount(view); nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many 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; 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; return false;
control.Add(vChecks); control.Add(vChecks);
} }
CTxUndo txundo; CTxUndo txundo;
tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i)); UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i));
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo); blockundo.vtxundo.push_back(txundo);
@ -1684,8 +1702,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
if (fBenchmark) 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)); 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)) if (GetValueOut(vtx[0]) > 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))); 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()) if (!control.Wait())
return state.DoS(100, false); return state.DoS(100, false);
@ -1847,7 +1865,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
BOOST_FOREACH(CTransaction& tx, vResurrect) { BOOST_FOREACH(CTransaction& tx, vResurrect) {
// ignore validation errors in resurrected transactions // ignore validation errors in resurrected transactions
CValidationState stateDummy; CValidationState stateDummy;
tx.AcceptToMemoryPool(stateDummy, true, false); mempool.accept(stateDummy, tx, true, false, NULL);
} }
// Delete redundant memory transactions that are in the connected branch // 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 // Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx) BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.CheckTransaction(state)) if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed"); return error("CheckBlock() : CheckTransaction failed");
// Build the merkle tree already. We need it anyway later, and it makes the // 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; unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx) BOOST_FOREACH(const CTransaction& tx, vtx)
{ {
nSigOps += tx.GetLegacySigOpCount(); nSigOps += GetLegacySigOpCount(tx);
} }
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); 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 // Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx) 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")); 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 // 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); 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) bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{ {
// Check for duplicate // Check for duplicate
@ -2253,7 +2282,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
// Ask this guy to fill in what we're missing // Ask this guy to fill in what we're missing
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2)); PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(pblock2));
} }
return true; return true;
} }
@ -3357,12 +3386,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!fImporting && !fReindex) if (!fImporting && !fReindex)
pfrom->AskFor(inv); pfrom->AskFor(inv);
} else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { } 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) { } else if (nInv == nLastBlock) {
// In case we are on a very long side-chain, it is possible that we already have // 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 // the last block in an inv bundle sent in response to getblocks. Try to detect
// this situation and push another getblocks to continue. // this situation and push another getblocks to continue.
pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0)); PushGetBlocks(pfrom, mapBlockIndex[inv.hash], uint256(0));
if (fDebug) if (fDebug)
printf("force request: %s\n", inv.ToString().c_str()); 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; bool fMissingInputs = false;
CValidationState state; CValidationState state;
if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs)) if (mempool.accept(state, tx, true, true, &fMissingInputs))
{ {
RelayTransaction(tx, inv.hash, vMsg); RelayTransaction(tx, inv.hash, vMsg);
mapAlreadyAskedFor.erase(inv); 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) // 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; 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()); printf(" accepted orphan tx %s\n", inv.hash.ToString().c_str());
RelayTransaction(tx, inv.hash, vMsg); RelayTransaction(tx, inv.hash, vMsg);
@ -3839,7 +3868,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// Start block sync // Start block sync
if (pto->fStartSync && !fImporting && !fReindex) { if (pto->fStartSync && !fImporting && !fReindex) {
pto->fStartSync = false; pto->fStartSync = false;
pto->PushGetBlocks(pindexBest, uint256(0)); PushGetBlocks(pto, pindexBest, uint256(0));
} }
// Resend wallet transactions that haven't gotten in a block yet // 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) for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
{ {
CTransaction& tx = (*mi).second; CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal()) if (tx.IsCoinBase() || !IsFinalTx(tx))
continue; continue;
COrphan* porphan = NULL; 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 // 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 // client code rounds up the size to the nearest 1K. That's good, because it gives an
// incentive to create smaller transactions. // 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) if (porphan)
{ {
@ -4275,7 +4304,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
continue; continue;
// Legacy limits on sigOps: // Legacy limits on sigOps:
unsigned int nTxSigOps = tx.GetLegacySigOpCount(); unsigned int nTxSigOps = GetLegacySigOpCount(tx);
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue; continue;
@ -4293,22 +4322,22 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
} }
if (!tx.HaveInputs(view)) if (!view.HaveInputs(tx))
continue; 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) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue; continue;
CValidationState state; CValidationState state;
if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH)) if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH))
continue; continue;
CTxUndo txundo; CTxUndo txundo;
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
tx.UpdateCoins(state, view, txundo, pindexPrev->nHeight+1, hash); UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
// Added // Added
pblock->vtx.push_back(tx); pblock->vtx.push_back(tx);
@ -4352,11 +4381,11 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Fill in header // Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->UpdateTime(pindexPrev); UpdateTime(*pblock, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
pblock->nNonce = 0; pblock->nNonce = 0;
pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_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); CBlockIndex indexDummy(*pblock);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
@ -4592,7 +4621,7 @@ void static BitcoinMiner(CWallet *pwallet)
break; break;
// Update nTime every few seconds // Update nTime every few seconds
pblock->UpdateTime(pindexPrev); UpdateTime(*pblock, pindexPrev);
nBlockTime = ByteReverse(pblock->nTime); nBlockTime = ByteReverse(pblock->nTime);
if (fTestNet) if (fTestNet)
{ {

850
src/main.h

@ -5,6 +5,7 @@
#ifndef BITCOIN_MAIN_H #ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H #define BITCOIN_MAIN_H
#include "core.h"
#include "bignum.h" #include "bignum.h"
#include "sync.h" #include "sync.h"
#include "net.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; static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** The maximum number of orphan transactions kept in memory */ /** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; 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) */ /** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
@ -122,6 +121,14 @@ void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn); void UnregisterWallet(CWallet* pwalletIn);
/** Push an updated transaction to all registered wallets */ /** Push an updated transaction to all registered wallets */
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); 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 */ /** Process an incoming block */
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */ /** 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); bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
/** Find the best known block, and make it the tip of the block chain */ /** Find the best known block, and make it the tip of the block chain */
bool ConnectBestBlock(CValidationState &state); bool ConnectBestBlock(CValidationState &state);
void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev);
/** Create a new block index entry for a given block hash */ /** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash); CBlockIndex * InsertBlockIndex(uint256 hash);
/** Verify a signature */ /** 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 enum GetMinFee_mode
{ {
@ -461,298 +267,72 @@ enum GetMinFee_mode
GMF_SEND, GMF_SEND,
}; };
/** The basic transaction that is broadcasted on the network and contained in int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, bool fAllowFree = true, enum GetMinFee_mode mode = GMF_BLOCK);
* 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 //
{ // Check transaction inputs, and make sure any
return SerializeHash(*this); // pay-to-script-hash transactions are evaluating IsStandard scripts
} //
// Why bother? To avoid denial-of-service attacks; an attacker
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const // can submit a standard HASH... OP_EQUAL transaction,
{ // which will get accepted into blocks. The redemption
// Time based nLockTime implemented in 0.1.6 // script can be anything; an attacker could use a very
if (nLockTime == 0) // expensive-to-check-upon-redemption script like:
return true; // DUP CHECKSIG DROP ... repeated 100 times... OP_1
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());
}
/** Check for standard transaction types
@return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
bool IsStandard() const;
/** Check for standard transaction types /** 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 @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 /** Count ECDSA signature operations the old-fashioned (pre-0.6) way
@return number of sigops this transaction's outputs will produce when spent @return number of sigops this transaction's outputs will produce when spent
*/ @see CTransaction::FetchInputs
unsigned int GetLegacySigOpCount() const; */
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 @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 @return maximum number of sigops required to validate this transaction's inputs
@see CTransaction::FetchInputs
*/ */
unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const; unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs);
/** 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) inline bool AllowFree(double dPriority)
{ {
// Large (in bytes) low-priority (new, small-coin) transactions // Large (in bytes) low-priority (new, small-coin) transactions
// need a fee. // need a fee.
return dPriority > COIN * 144 / 250; 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 // 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
printf("%s", ToString().c_str()); // instead of being performed inline.
} bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
// 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, unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
std::vector<CScriptCheck> *pvChecks = NULL) const; std::vector<CScriptCheck> *pvChecks = NULL);
// Apply the effects of this transaction on the UTXO set represented by view // 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; bool UpdateCoins(const CTransaction& tx, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash);
// Context-independent validity checks // Context-independent validity checks
bool CheckTransaction(CValidationState &state) const; bool CheckTransaction(const CTransaction& tx, CValidationState& state);
// Try to accept this transaction into the memory pool
bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL);
protected:
static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
};
/** wrapper for CTxOut that provides a more compact serialization */ /** Check for standard transaction types
class CTxOutCompressor @return True if all outputs (scriptPubKeys) use only standard transaction forms
{ */
private: bool IsStandardTx(const CTransaction& tx);
CTxOut &txout;
public:
static uint64 CompressAmount(uint64 nAmount);
static uint64 DecompressAmount(uint64 nAmount);
CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
IMPLEMENT_SERIALIZE(({ bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0);
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 /** Amount of bitcoins spent by the transaction.
* @return sum of all outputs (note: does not include fees)
* 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 int64 GetValueOut(const CTransaction& tx);
{
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);
)
};
/** Undo information for a CBlock */ /** Undo information for a CBlock */
class CBlockUndo 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 /** Closure representing one script verification
* Note that this stores references to the spending transaction */ * 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 class CBlock : public CBlockHeader
{ {
public: public:
@ -2183,6 +1452,21 @@ public:
// Calculate the size of the cache (in number of transactions) // Calculate the size of the cache (in number of transactions)
unsigned int GetCacheSize(); 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: private:
std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid); std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid);
}; };

1
src/makefile.linux-mingw

@ -73,6 +73,7 @@ OBJS= \
obj/init.o \ obj/init.o \
obj/bitcoind.o \ obj/bitcoind.o \
obj/keystore.o \ obj/keystore.o \
obj/core.o \
obj/main.o \ obj/main.o \
obj/net.o \ obj/net.o \
obj/protocol.o \ obj/protocol.o \

1
src/makefile.mingw

@ -81,6 +81,7 @@ OBJS= \
obj/init.o \ obj/init.o \
obj/bitcoind.o \ obj/bitcoind.o \
obj/keystore.o \ obj/keystore.o \
obj/core.o \
obj/main.o \ obj/main.o \
obj/net.o \ obj/net.o \
obj/protocol.o \ obj/protocol.o \

1
src/makefile.osx vendored

@ -84,6 +84,7 @@ OBJS= \
obj/init.o \ obj/init.o \
obj/bitcoind.o \ obj/bitcoind.o \
obj/keystore.o \ obj/keystore.o \
obj/core.o \
obj/main.o \ obj/main.o \
obj/net.o \ obj/net.o \
obj/protocol.o \ obj/protocol.o \

1
src/makefile.unix

@ -123,6 +123,7 @@ OBJS= \
obj/init.o \ obj/init.o \
obj/bitcoind.o \ obj/bitcoind.o \
obj/keystore.o \ obj/keystore.o \
obj/core.o \
obj/main.o \ obj/main.o \
obj/net.o \ obj/net.o \
obj/protocol.o \ obj/protocol.o \

28
src/net.cpp

@ -5,7 +5,7 @@
#include "db.h" #include "db.h"
#include "net.h" #include "net.h"
#include "init.h" #include "core.h"
#include "addrman.h" #include "addrman.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "script.h" #include "script.h"
@ -68,6 +68,10 @@ CCriticalSection cs_vAddedNodes;
static CSemaphore *semOutbound = NULL; static CSemaphore *semOutbound = NULL;
// Signals for message handling
static CNodeSignals g_signals;
CNodeSignals& GetNodeSignals() { return g_signals; }
void AddOneShot(string strDest) void AddOneShot(string strDest)
{ {
LOCK(cs_vOneShots); LOCK(cs_vOneShots);
@ -79,17 +83,6 @@ unsigned short GetListenPort()
return (unsigned short)(GetArg("-port", GetDefaultPort())); 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 // find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer) bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{ {
@ -1574,11 +1567,6 @@ void static StartSync(const vector<CNode*> &vNodes) {
CNode *pnodeNewSync = NULL; CNode *pnodeNewSync = NULL;
double dBestScore = 0; 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 // Iterate over all nodes
BOOST_FOREACH(CNode* pnode, vNodes) { BOOST_FOREACH(CNode* pnode, vNodes) {
// check preconditions for allowing a sync // check preconditions for allowing a sync
@ -1635,7 +1623,7 @@ void ThreadMessageHandler()
{ {
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv) if (lockRecv)
if (!ProcessMessages(pnode)) if (!g_signals.ProcessMessages(pnode))
pnode->CloseSocketDisconnect(); pnode->CloseSocketDisconnect();
} }
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
@ -1644,7 +1632,7 @@ void ThreadMessageHandler()
{ {
TRY_LOCK(pnode->cs_vSend, lockSend); TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend) if (lockSend)
SendMessages(pnode, pnode == pnodeTrickle); g_signals.SendMessages(pnode, pnode == pnodeTrickle);
} }
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
@ -1861,9 +1849,7 @@ void StartNode(boost::thread_group& threadGroup)
bool StopNode() bool StopNode()
{ {
printf("StopNode()\n"); printf("StopNode()\n");
GenerateBitcoins(false, NULL);
MapPort(false); MapPort(false);
nTransactionsUpdated++;
if (semOutbound) if (semOutbound)
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
semOutbound->post(); semOutbound->post();

15
src/net.h

@ -8,6 +8,7 @@
#include <deque> #include <deque>
#include <boost/array.hpp> #include <boost/array.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/signals2/signal.hpp>
#include <openssl/rand.h> #include <openssl/rand.h>
#ifndef WIN32 #ifndef WIN32
@ -22,6 +23,9 @@
#include "hash.h" #include "hash.h"
#include "bloom.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 CNode;
class CBlockIndex; class CBlockIndex;
extern int nBestHeight; extern int nBestHeight;
@ -45,6 +49,16 @@ void StartNode(boost::thread_group& threadGroup);
bool StopNode(); bool StopNode();
void SocketSendData(CNode *pnode); 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 enum
{ {
LOCAL_NONE, // unknown LOCAL_NONE, // unknown
@ -600,7 +614,6 @@ public:
} }
} }
void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
bool IsSubscribed(unsigned int nChannel); bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0); void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel); void CancelSubscribe(unsigned int nChannel);

1
src/protocol.cpp

@ -6,7 +6,6 @@
#include "protocol.h" #include "protocol.h"
#include "util.h" #include "util.h"
#include "netbase.h" #include "netbase.h"
#include "main.h"
#ifndef WIN32 #ifndef WIN32
# include <arpa/inet.h> # include <arpa/inet.h>

4
src/qt/transactiondesc.cpp

@ -12,7 +12,7 @@
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{ {
if (!wtx.IsFinal()) if (!IsFinalTx(wtx))
{ {
if (wtx.nLockTime < LOCKTIME_THRESHOLD) if (wtx.nLockTime < LOCKTIME_THRESHOLD)
return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight + 1); 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>"; strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
} }
int64 nTxFee = nDebit - wtx.GetValueOut(); int64 nTxFee = nDebit - GetValueOut(wtx);
if (nTxFee > 0) if (nTxFee > 0)
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>"; strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>";
} }

4
src/qt/transactionrecord.cpp

@ -89,7 +89,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
// //
// Debit // Debit
// //
int64 nTxFee = nDebit - wtx.GetValueOut(); int64 nTxFee = nDebit - GetValueOut(wtx);
for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) 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.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = nBestHeight; status.cur_num_blocks = nBestHeight;
if (!wtx.IsFinal()) if (!IsFinalTx(wtx))
{ {
if (wtx.nLockTime < LOCKTIME_THRESHOLD) if (wtx.nLockTime < LOCKTIME_THRESHOLD)
{ {

4
src/rpcmining.cpp

@ -159,7 +159,7 @@ Value getwork(const Array& params, bool fHelp)
CBlock* pblock = &pblocktemplate->block; // pointer for convenience CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime // Update nTime
pblock->UpdateTime(pindexPrev); UpdateTime(*pblock, pindexPrev);
pblock->nNonce = 0; pblock->nNonce = 0;
// Update nExtraNonce // Update nExtraNonce
@ -289,7 +289,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
CBlock* pblock = &pblocktemplate->block; // pointer for convenience CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime // Update nTime
pblock->UpdateTime(pindexPrev); UpdateTime(*pblock, pindexPrev);
pblock->nNonce = 0; pblock->nNonce = 0;
Array transactions; Array transactions;

2
src/rpcrawtransaction.cpp

@ -555,7 +555,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
if (!fHave) { if (!fHave) {
// push to local node // push to local node
CValidationState state; 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 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
} }
} }

10
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) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal()) if (wtx.IsCoinBase() || !IsFinalTx(wtx))
continue; continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) 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) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal()) if (wtx.IsCoinBase() || !IsFinalTx(wtx))
continue; continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) 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) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal()) if (!IsFinalTx(wtx))
continue; continue;
int64 nReceived, nSent, nFee; int64 nReceived, nSent, nFee;
@ -839,7 +839,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal()) if (wtx.IsCoinBase() || !IsFinalTx(wtx))
continue; continue;
int nDepth = wtx.GetDepthInMainChain(); int nDepth = wtx.GetDepthInMainChain();
@ -1220,7 +1220,7 @@ Value gettransaction(const Array& params, bool fHelp)
int64 nCredit = wtx.GetCredit(); int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit(); int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit; 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))); entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe()) if (wtx.IsFromMe())

2
src/script.cpp

@ -9,10 +9,10 @@ using namespace std;
using namespace boost; using namespace boost;
#include "script.h" #include "script.h"
#include "core.h"
#include "keystore.h" #include "keystore.h"
#include "bignum.h" #include "bignum.h"
#include "key.h" #include "key.h"
#include "main.h"
#include "sync.h" #include "sync.h"
#include "util.h" #include "util.h"

2
src/script.h

@ -533,7 +533,7 @@ public:
bool IsPayToScriptHash() const; bool IsPayToScriptHash() const;
// Called by CTransaction::IsStandard // Called by IsStandardTx
bool IsPushOnly() const bool IsPushOnly() const
{ {
const_iterator pc = begin(); const_iterator pc = begin();

2
src/test/data/tx_invalid.json

@ -23,7 +23,7 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true], "010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true],
["Tests for CTransaction::CheckTransaction()"], ["Tests for CheckTransaction()"],
["No inputs"], ["No inputs"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
"0100000000010000000000000000015100000000", true], "0100000000010000000000000000015100000000", true],

2
src/test/data/tx_valid.json

@ -50,7 +50,7 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true], "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true],
["Tests for CTransaction::CheckTransaction()"], ["Tests for CheckTransaction()"],
["MAX_MONEY output"], ["MAX_MONEY output"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true], "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true],

18
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].scriptPubKey = standardScripts[i];
txFrom.vout[i+4].nValue = COIN; txFrom.vout[i+4].nValue = COIN;
} }
BOOST_CHECK(txFrom.IsStandard()); BOOST_CHECK(IsStandardTx(txFrom));
CTransaction txTo[8]; // Spending transactions CTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++) 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].scriptPubKey = outer[i];
txFrom.vout[i].nValue = CENT; txFrom.vout[i].nValue = CENT;
} }
BOOST_CHECK(txFrom.IsStandard()); BOOST_CHECK(IsStandardTx(txFrom));
CTransaction txTo[4]; // Spending transactions CTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(set)
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", 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(); txTo.vin[2].prevout.hash = txFrom.GetHash();
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
BOOST_CHECK(txTo.AreInputsStandard(coins)); BOOST_CHECK(::AreInputsStandard(txTo, coins));
BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(coins), 1U); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 1U);
// Make sure adding crap to the scriptSigs makes them non-standard: // Make sure adding crap to the scriptSigs makes them non-standard:
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
CScript t = txTo.vin[i].scriptSig; CScript t = txTo.vin[i].scriptSig;
txTo.vin[i].scriptSig = (CScript() << 11) + t; txTo.vin[i].scriptSig = (CScript() << 11) + t;
BOOST_CHECK(!txTo.AreInputsStandard(coins)); BOOST_CHECK(!::AreInputsStandard(txTo, coins));
txTo.vin[i].scriptSig = t; txTo.vin[i].scriptSig = t;
} }
@ -329,11 +329,11 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd.vin[1].prevout.hash = txFrom.GetHash(); txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven); txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
BOOST_CHECK(!txToNonStd.AreInputsStandard(coins)); BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(coins), 11U); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd, coins), 11U);
txToNonStd.vin[0].scriptSig.clear(); txToNonStd.vin[0].scriptSig.clear();
BOOST_CHECK(!txToNonStd.AreInputsStandard(coins)); BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

24
src/test/transaction_tests.cpp

@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
BOOST_CHECK_MESSAGE(tx.CheckTransaction(state), strTest); BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid()); BOOST_CHECK(state.IsValid());
for (unsigned int i = 0; i < tx.vin.size(); i++) for (unsigned int i = 0; i < tx.vin.size(); i++)
@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
stream >> tx; stream >> tx;
CValidationState state; 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++) for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{ {
@ -163,11 +163,11 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CTransaction tx; CTransaction tx;
stream >> tx; stream >> tx;
CValidationState state; 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 // Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]); 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].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1; t1.vout[0].scriptPubKey << OP_1;
BOOST_CHECK(t1.AreInputsStandard(coins)); BOOST_CHECK(AreInputsStandard(t1, coins));
BOOST_CHECK_EQUAL(t1.GetValueIn(coins), (50+21+22)*CENT); BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
// Adding extra junk to the scriptSig should make it non-standard: // Adding extra junk to the scriptSig should make it non-standard:
t1.vin[0].scriptSig << OP_11; t1.vin[0].scriptSig << OP_11;
BOOST_CHECK(!t1.AreInputsStandard(coins)); BOOST_CHECK(!AreInputsStandard(t1, coins));
// ... as should not having enough: // ... as should not having enough:
t1.vin[0].scriptSig = CScript(); t1.vin[0].scriptSig = CScript();
BOOST_CHECK(!t1.AreInputsStandard(coins)); BOOST_CHECK(!AreInputsStandard(t1, coins));
} }
BOOST_AUTO_TEST_CASE(test_IsStandard) BOOST_AUTO_TEST_CASE(test_IsStandard)
@ -260,16 +260,16 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
key.MakeNewKey(true); key.MakeNewKey(true);
t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
BOOST_CHECK(t.IsStandard()); BOOST_CHECK(IsStandardTx(t));
t.vout[0].nValue = 5011; // dust t.vout[0].nValue = 5011; // dust
BOOST_CHECK(!t.IsStandard()); BOOST_CHECK(!IsStandardTx(t));
t.vout[0].nValue = 6011; // not dust t.vout[0].nValue = 6011; // not dust
BOOST_CHECK(t.IsStandard()); BOOST_CHECK(IsStandardTx(t));
t.vout[0].scriptPubKey = CScript() << OP_1; t.vout[0].scriptPubKey = CScript() << OP_1;
BOOST_CHECK(!t.IsStandard()); BOOST_CHECK(!IsStandardTx(t));
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

16
src/wallet.cpp

@ -643,7 +643,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived,
int64 nDebit = GetDebit(); int64 nDebit = GetDebit();
if (nDebit > 0) // debit>0 means we signed/sent this transaction if (nDebit > 0) // debit>0 means we signed/sent this transaction
{ {
int64 nValueOut = GetValueOut(); int64 nValueOut = GetValueOut(*this);
nFee = nDebit - nValueOut; nFee = nDebit - nValueOut;
} }
@ -933,7 +933,7 @@ int64 CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{ {
const CWalletTx* pcoin = &(*it).second; const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
nTotal += pcoin->GetAvailableCredit(); nTotal += pcoin->GetAvailableCredit();
} }
} }
@ -965,7 +965,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
{ {
const CWalletTx* pcoin = &(*it).second; const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal()) if (!IsFinalTx(*pcoin))
continue; continue;
if (fOnlyConfirmed && !pcoin->IsConfirmed()) 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) BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
{ {
CTxOut txout(s.second, s.first); CTxOut txout(s.second, s.first);
if (txout.IsDust()) if (txout.IsDust(CTransaction::nMinRelayTxFee))
{ {
strFailReason = _("Transaction amount too small"); strFailReason = _("Transaction amount too small");
return false; return false;
@ -1237,7 +1237,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
// Never create dust outputs; if we would, just // Never create dust outputs; if we would, just
// add the dust to the fee. // add the dust to the fee.
if (newTxOut.IsDust()) if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
{ {
nFeeRet += nChange; nFeeRet += nChange;
reservekey.ReturnKey(); reservekey.ReturnKey();
@ -1276,8 +1276,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
// Check that enough fee is included // Check that enough fee is included
int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
bool fAllowFree = CTransaction::AllowFree(dPriority); bool fAllowFree = AllowFree(dPriority);
int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND); int64 nMinFee = GetMinFee(wtxNew, 1, fAllowFree, GMF_SEND);
if (nFeeRet < max(nPayFee, nMinFee)) if (nFeeRet < max(nPayFee, nMinFee))
{ {
nFeeRet = max(nPayFee, nMinFee); nFeeRet = max(nPayFee, nMinFee);
@ -1657,7 +1657,7 @@ std::map<CTxDestination, int64> CWallet::GetAddressBalances()
{ {
CWalletTx *pcoin = &walletEntry.second; CWalletTx *pcoin = &walletEntry.second;
if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
continue; continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)

8
src/wallet.h

@ -5,6 +5,8 @@
#ifndef BITCOIN_WALLET_H #ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H #define BITCOIN_WALLET_H
#include "walletdb.h"
#include <string> #include <string>
#include <vector> #include <vector>
@ -16,12 +18,12 @@
#include "script.h" #include "script.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "util.h" #include "util.h"
#include "walletdb.h"
class CAccountingEntry; class CAccountingEntry;
class CWalletTx; class CWalletTx;
class CReserveKey; class CReserveKey;
class COutput; class COutput;
class CWalletDB;
/** (client) version numbers for particular wallet features */ /** (client) version numbers for particular wallet features */
enum WalletFeature enum WalletFeature
@ -639,7 +641,7 @@ public:
bool IsConfirmed() const bool IsConfirmed() const
{ {
// Quick answer in most cases // Quick answer in most cases
if (!IsFinal()) if (!IsFinalTx(*this))
return false; return false;
if (GetDepthInMainChain() >= 1) if (GetDepthInMainChain() >= 1)
return true; return true;
@ -656,7 +658,7 @@ public:
{ {
const CMerkleTx* ptx = vWorkQueue[i]; const CMerkleTx* ptx = vWorkQueue[i];
if (!ptx->IsFinal()) if (!IsFinalTx(*ptx))
return false; return false;
if (ptx->GetDepthInMainChain() >= 1) if (ptx->GetDepthInMainChain() >= 1)
continue; continue;

2
src/walletdb.cpp

@ -204,7 +204,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx& wtx = pwallet->mapWallet[hash]; CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx; ssValue >> wtx;
CValidationState state; CValidationState state;
if (wtx.CheckTransaction(state) && (wtx.GetHash() == hash) && state.IsValid()) if (CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid())
wtx.BindWallet(pwallet); wtx.BindWallet(pwallet);
else else
{ {

4
src/walletdb.h

@ -11,6 +11,8 @@
class CKeyPool; class CKeyPool;
class CAccount; class CAccount;
class CAccountingEntry; class CAccountingEntry;
class CWallet;
class CWalletTx;
/** Error statuses for the wallet database */ /** Error statuses for the wallet database */
enum DBErrors enum DBErrors
@ -160,4 +162,6 @@ public:
static bool Recover(CDBEnv& dbenv, std::string filename); static bool Recover(CDBEnv& dbenv, std::string filename);
}; };
bool BackupWallet(const CWallet& wallet, const std::string& strDest);
#endif // BITCOIN_WALLETDB_H #endif // BITCOIN_WALLETDB_H

Loading…
Cancel
Save