Merge pull request #2154 from CodeShark/dependencycleanup

Clean up code dependencies
This commit is contained in:
Jeff Garzik 2013-06-10 06:17:38 -07:00
commit f59530ce6e
30 changed files with 1104 additions and 1024 deletions

View File

@ -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 Normal file
View File

@ -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 Normal file
View File

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

View File

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

View File

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

View File

@ -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");

View File

@ -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, if (tx.nVersion > CTransaction::CURRENT_VERSION)
// 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)
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)
{ {

View File

@ -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() //
{ // Check transaction inputs, and make sure any
SetNull(); // pay-to-script-hash transactions are evaluating IsStandard scripts
} //
// Why bother? To avoid denial-of-service attacks; an attacker
IMPLEMENT_SERIALIZE // can submit a standard HASH... OP_EQUAL transaction,
( // which will get accepted into blocks. The redemption
READWRITE(this->nVersion); // script can be anything; an attacker could use a very
nVersion = this->nVersion; // expensive-to-check-upon-redemption script like:
READWRITE(vin); // DUP CHECKSIG DROP ... repeated 100 times... OP_1
READWRITE(vout); //
READWRITE(nLockTime);
)
void SetNull()
{
nVersion = CTransaction::CURRENT_VERSION;
vin.clear();
vout.clear();
nLockTime = 0;
}
bool IsNull() const
{
return (vin.empty() && vout.empty());
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
{
// Time based nLockTime implemented in 0.1.6
if (nLockTime == 0)
return true;
if (nBlockHeight == 0)
nBlockHeight = nBestHeight;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.IsFinal())
return false;
return true;
}
bool IsNewerThan(const CTransaction& old) const
{
if (vin.size() != old.vin.size())
return false;
for (unsigned int i = 0; i < vin.size(); i++)
if (vin[i].prevout != old.vin[i].prevout)
return false;
bool fNewer = false;
unsigned int nLowest = std::numeric_limits<unsigned int>::max();
for (unsigned int i = 0; i < vin.size(); i++)
{
if (vin[i].nSequence != old.vin[i].nSequence)
{
if (vin[i].nSequence <= nLowest)
{
fNewer = false;
nLowest = vin[i].nSequence;
}
if (old.vin[i].nSequence < nLowest)
{
fNewer = true;
nLowest = old.vin[i].nSequence;
}
}
}
return fNewer;
}
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull());
}
/** 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 inline bool AllowFree(double dPriority)
Note that lightweight clients may not know anything besides the hash of previous transactions,
so may not be able to calculate this.
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return Sum of value of all inputs (scriptSigs)
*/
int64 GetValueIn(CCoinsViewCache& mapInputs) const;
static bool AllowFree(double dPriority)
{ {
// Large (in bytes) low-priority (new, small-coin) transactions // 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
{
printf("%s", ToString().c_str());
}
// Check whether all prevouts of this transaction are present in the UTXO set represented by view
bool HaveInputs(CCoinsViewCache &view) const;
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) // 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 // This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
// instead of being performed inline. // instead of being performed inline.
bool CheckInputs(CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true, bool CheckInputs(const CTransaction& tx, 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 /** Check for standard transaction types
bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL); @return True if all outputs (scriptPubKeys) use only standard transaction forms
protected:
static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
};
/** 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 bool IsStandardTx(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) {} bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 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 { /** Amount of bitcoins spent by the transaction.
return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) + @return sum of all outputs (note: does not include fees)
(nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) + */
::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion); int64 GetValueOut(const CTransaction& tx);
}
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);
}; };

View File

@ -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 \

View File

@ -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 \

View File

@ -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 \

View File

@ -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 \

View File

@ -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();

View File

@ -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);

View File

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

View File

@ -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>";
} }

View File

@ -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)
{ {

View File

@ -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;

View File

@ -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
} }
} }

View File

@ -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())

View File

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

View File

@ -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();

View File

@ -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],

View File

@ -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],

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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;

View File

@ -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
{ {

View File

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