mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-12 16:17:53 +00:00
Merge pull request #2154 from CodeShark/dependencycleanup
Clean up code dependencies
This commit is contained in:
commit
f59530ce6e
@ -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
7
src/core.cpp
Normal 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
736
src/core.h
Normal 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
|
11
src/db.cpp
11
src/db.cpp
@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "main.h"
|
#include "hash.h"
|
||||||
|
#include "addrman.h"
|
||||||
#include <boost/version.hpp>
|
#include <boost/version.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include "sys/stat.h"
|
#include "sys/stat.h"
|
||||||
@ -486,6 +488,7 @@ void CDBEnv::Flush(bool fShutdown)
|
|||||||
// CAddrDB
|
// CAddrDB
|
||||||
//
|
//
|
||||||
|
|
||||||
|
unsigned char CAddrDB::pchMessageStart[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
CAddrDB::CAddrDB()
|
CAddrDB::CAddrDB()
|
||||||
{
|
{
|
||||||
@ -501,7 +504,7 @@ bool CAddrDB::Write(const CAddrMan& addr)
|
|||||||
|
|
||||||
// serialize addresses, checksum data up to that point, then append csum
|
// serialize addresses, checksum data up to that point, then append csum
|
||||||
CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
|
CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
|
||||||
ssPeers << FLATDATA(pchMessageStart);
|
ssPeers << FLATDATA(CAddrDB::pchMessageStart);
|
||||||
ssPeers << addr;
|
ssPeers << addr;
|
||||||
uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
|
uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
|
||||||
ssPeers << hash;
|
ssPeers << hash;
|
||||||
@ -566,11 +569,11 @@ bool CAddrDB::Read(CAddrMan& addr)
|
|||||||
|
|
||||||
unsigned char pchMsgTmp[4];
|
unsigned char pchMsgTmp[4];
|
||||||
try {
|
try {
|
||||||
// de-serialize file header (pchMessageStart magic number) and
|
// de-serialize file header (CAddrDB::pchMessageStart magic number) and
|
||||||
ssPeers >> FLATDATA(pchMsgTmp);
|
ssPeers >> FLATDATA(pchMsgTmp);
|
||||||
|
|
||||||
// verify the network matches ours
|
// verify the network matches ours
|
||||||
if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp)))
|
if (memcmp(pchMsgTmp, CAddrDB::pchMessageStart, sizeof(pchMsgTmp)))
|
||||||
return error("CAddrman::Read() : invalid network magic number");
|
return error("CAddrman::Read() : invalid network magic number");
|
||||||
|
|
||||||
// de-serialize address data into one CAddrMan object
|
// de-serialize address data into one CAddrMan object
|
||||||
|
10
src/db.h
10
src/db.h
@ -5,22 +5,22 @@
|
|||||||
#ifndef BITCOIN_DB_H
|
#ifndef BITCOIN_DB_H
|
||||||
#define BITCOIN_DB_H
|
#define BITCOIN_DB_H
|
||||||
|
|
||||||
#include "main.h"
|
#include "sync.h"
|
||||||
|
#include "serialize.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include <db_cxx.h>
|
#include <db_cxx.h>
|
||||||
|
|
||||||
class CAddress;
|
|
||||||
class CAddrMan;
|
class CAddrMan;
|
||||||
class CBlockLocator;
|
class CBlockLocator;
|
||||||
class CDiskBlockIndex;
|
class CDiskBlockIndex;
|
||||||
class CMasterKey;
|
class CMasterKey;
|
||||||
class COutPoint;
|
class COutPoint;
|
||||||
class CWallet;
|
class CWallet;
|
||||||
class CWalletTx;
|
|
||||||
|
|
||||||
extern unsigned int nWalletDBUpdated;
|
extern unsigned int nWalletDBUpdated;
|
||||||
|
|
||||||
@ -318,10 +318,14 @@ class CAddrDB
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
boost::filesystem::path pathAddr;
|
boost::filesystem::path pathAddr;
|
||||||
|
static unsigned char pchMessageStart[4];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAddrDB();
|
CAddrDB();
|
||||||
bool Write(const CAddrMan& addr);
|
bool Write(const CAddrMan& addr);
|
||||||
bool Read(CAddrMan& addr);
|
bool Read(CAddrMan& addr);
|
||||||
|
|
||||||
|
static void SetMessageStart(unsigned char _pchMessageStart[]) { memcpy(CAddrDB::pchMessageStart, _pchMessageStart, sizeof(CAddrDB::pchMessageStart)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_DB_H
|
#endif // BITCOIN_DB_H
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "init.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "core.h"
|
||||||
#include "txdb.h"
|
#include "txdb.h"
|
||||||
#include "walletdb.h"
|
#include "walletdb.h"
|
||||||
#include "bitcoinrpc.h"
|
#include "bitcoinrpc.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "init.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
@ -45,6 +47,7 @@ enum BindFlags {
|
|||||||
BF_REPORT_ERROR = (1U << 1)
|
BF_REPORT_ERROR = (1U << 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Shutdown
|
// Shutdown
|
||||||
@ -99,6 +102,7 @@ void Shutdown()
|
|||||||
StopRPCThreads();
|
StopRPCThreads();
|
||||||
ShutdownRPCMining();
|
ShutdownRPCMining();
|
||||||
bitdb.Flush(false);
|
bitdb.Flush(false);
|
||||||
|
GenerateBitcoins(false, NULL);
|
||||||
StopNode();
|
StopNode();
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
@ -567,6 +571,8 @@ bool AppInit2(boost::thread_group& threadGroup)
|
|||||||
|
|
||||||
// ********************************************************* Step 6: network initialization
|
// ********************************************************* Step 6: network initialization
|
||||||
|
|
||||||
|
RegisterNodeSignals(GetNodeSignals());
|
||||||
|
|
||||||
int nSocksVersion = GetArg("-socks", 5);
|
int nSocksVersion = GetArg("-socks", 5);
|
||||||
if (nSocksVersion != 4 && nSocksVersion != 5)
|
if (nSocksVersion != 4 && nSocksVersion != 5)
|
||||||
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
|
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
|
||||||
@ -928,6 +934,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
|||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
CAddrDB::SetMessageStart(pchMessageStart);
|
||||||
CAddrDB adb;
|
CAddrDB adb;
|
||||||
if (!adb.Read(addrman))
|
if (!adb.Read(addrman))
|
||||||
printf("Invalid or missing peers.dat; recreating\n");
|
printf("Invalid or missing peers.dat; recreating\n");
|
||||||
|
331
src/main.cpp
331
src/main.cpp
@ -160,7 +160,22 @@ void static ResendWalletTransactions()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Registration of network node signals.
|
||||||
|
//
|
||||||
|
|
||||||
|
void RegisterNodeSignals(CNodeSignals& nodeSignals)
|
||||||
|
{
|
||||||
|
nodeSignals.ProcessMessages.connect(&ProcessMessages);
|
||||||
|
nodeSignals.SendMessages.connect(&SendMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
|
||||||
|
{
|
||||||
|
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
|
||||||
|
nodeSignals.SendMessages.disconnect(&SendMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -357,41 +372,23 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
bool IsStandardTx(const CTransaction& tx)
|
||||||
//
|
|
||||||
// CTransaction / CTxOut
|
|
||||||
//
|
|
||||||
|
|
||||||
bool CTxOut::IsDust() const
|
|
||||||
{
|
{
|
||||||
// "Dust" is defined in terms of CTransaction::nMinRelayTxFee,
|
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)
|
||||||
{
|
{
|
||||||
|
830
src/main.h
830
src/main.h
@ -5,6 +5,7 @@
|
|||||||
#ifndef BITCOIN_MAIN_H
|
#ifndef BITCOIN_MAIN_H
|
||||||
#define BITCOIN_MAIN_H
|
#define BITCOIN_MAIN_H
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
#include "bignum.h"
|
#include "bignum.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
@ -34,8 +35,6 @@ static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5;
|
|||||||
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
|
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
|
||||||
/** The maximum number of orphan transactions kept in memory */
|
/** The maximum number of orphan transactions kept in memory */
|
||||||
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
|
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
|
||||||
/** The maximum number of entries in an 'inv' protocol message */
|
|
||||||
static const unsigned int MAX_INV_SZ = 50000;
|
|
||||||
/** The maximum size of a blk?????.dat file (since 0.8) */
|
/** The maximum size of a blk?????.dat file (since 0.8) */
|
||||||
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
|
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
|
||||||
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
|
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
|
||||||
@ -122,6 +121,14 @@ void RegisterWallet(CWallet* pwalletIn);
|
|||||||
void UnregisterWallet(CWallet* pwalletIn);
|
void UnregisterWallet(CWallet* pwalletIn);
|
||||||
/** Push an updated transaction to all registered wallets */
|
/** Push an updated transaction to all registered wallets */
|
||||||
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
|
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
|
||||||
|
|
||||||
|
/** Register with a network node to receive its signals */
|
||||||
|
void RegisterNodeSignals(CNodeSignals& nodeSignals);
|
||||||
|
/** Unregister a network node */
|
||||||
|
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
|
||||||
|
|
||||||
|
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
|
||||||
|
|
||||||
/** Process an incoming block */
|
/** Process an incoming block */
|
||||||
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
|
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
|
||||||
/** Check whether enough disk space is available for an incoming block */
|
/** Check whether enough disk space is available for an incoming block */
|
||||||
@ -176,6 +183,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b
|
|||||||
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
|
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
|
||||||
/** Find the best known block, and make it the tip of the block chain */
|
/** Find the best known block, and make it the tip of the block chain */
|
||||||
bool ConnectBestBlock(CValidationState &state);
|
bool ConnectBestBlock(CValidationState &state);
|
||||||
|
|
||||||
|
void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev);
|
||||||
|
|
||||||
/** Create a new block index entry for a given block hash */
|
/** Create a new block index entry for a given block hash */
|
||||||
CBlockIndex * InsertBlockIndex(uint256 hash);
|
CBlockIndex * InsertBlockIndex(uint256 hash);
|
||||||
/** Verify a signature */
|
/** Verify a signature */
|
||||||
@ -249,210 +259,6 @@ struct CDiskTxPos : public CDiskBlockPos
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** An inpoint - a combination of a transaction and an index n into its vin */
|
|
||||||
class CInPoint
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CTransaction* ptx;
|
|
||||||
unsigned int n;
|
|
||||||
|
|
||||||
CInPoint() { SetNull(); }
|
|
||||||
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
|
|
||||||
void SetNull() { ptx = NULL; n = (unsigned int) -1; }
|
|
||||||
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
|
||||||
class COutPoint
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
uint256 hash;
|
|
||||||
unsigned int n;
|
|
||||||
|
|
||||||
COutPoint() { SetNull(); }
|
|
||||||
COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
|
|
||||||
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
|
|
||||||
void SetNull() { hash = 0; n = (unsigned int) -1; }
|
|
||||||
bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); }
|
|
||||||
|
|
||||||
friend bool operator<(const COutPoint& a, const COutPoint& b)
|
|
||||||
{
|
|
||||||
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator==(const COutPoint& a, const COutPoint& b)
|
|
||||||
{
|
|
||||||
return (a.hash == b.hash && a.n == b.n);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const COutPoint& a, const COutPoint& b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ToString() const
|
|
||||||
{
|
|
||||||
return strprintf("COutPoint(%s, %u)", hash.ToString().c_str(), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() const
|
|
||||||
{
|
|
||||||
printf("%s\n", ToString().c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** An input of a transaction. It contains the location of the previous
|
|
||||||
* transaction's output that it claims and a signature that matches the
|
|
||||||
* output's public key.
|
|
||||||
*/
|
|
||||||
class CTxIn
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
COutPoint prevout;
|
|
||||||
CScript scriptSig;
|
|
||||||
unsigned int nSequence;
|
|
||||||
|
|
||||||
CTxIn()
|
|
||||||
{
|
|
||||||
nSequence = std::numeric_limits<unsigned int>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
|
|
||||||
{
|
|
||||||
prevout = prevoutIn;
|
|
||||||
scriptSig = scriptSigIn;
|
|
||||||
nSequence = nSequenceIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
|
|
||||||
{
|
|
||||||
prevout = COutPoint(hashPrevTx, nOut);
|
|
||||||
scriptSig = scriptSigIn;
|
|
||||||
nSequence = nSequenceIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMPLEMENT_SERIALIZE
|
|
||||||
(
|
|
||||||
READWRITE(prevout);
|
|
||||||
READWRITE(scriptSig);
|
|
||||||
READWRITE(nSequence);
|
|
||||||
)
|
|
||||||
|
|
||||||
bool IsFinal() const
|
|
||||||
{
|
|
||||||
return (nSequence == std::numeric_limits<unsigned int>::max());
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator==(const CTxIn& a, const CTxIn& b)
|
|
||||||
{
|
|
||||||
return (a.prevout == b.prevout &&
|
|
||||||
a.scriptSig == b.scriptSig &&
|
|
||||||
a.nSequence == b.nSequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const CTxIn& a, const CTxIn& b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ToString() const
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
str += "CTxIn(";
|
|
||||||
str += prevout.ToString();
|
|
||||||
if (prevout.IsNull())
|
|
||||||
str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
|
|
||||||
else
|
|
||||||
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
|
|
||||||
if (nSequence != std::numeric_limits<unsigned int>::max())
|
|
||||||
str += strprintf(", nSequence=%u", nSequence);
|
|
||||||
str += ")";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() const
|
|
||||||
{
|
|
||||||
printf("%s\n", ToString().c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** An output of a transaction. It contains the public key that the next input
|
|
||||||
* must be able to sign with to claim it.
|
|
||||||
*/
|
|
||||||
class CTxOut
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
int64 nValue;
|
|
||||||
CScript scriptPubKey;
|
|
||||||
|
|
||||||
CTxOut()
|
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
|
|
||||||
{
|
|
||||||
nValue = nValueIn;
|
|
||||||
scriptPubKey = scriptPubKeyIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMPLEMENT_SERIALIZE
|
|
||||||
(
|
|
||||||
READWRITE(nValue);
|
|
||||||
READWRITE(scriptPubKey);
|
|
||||||
)
|
|
||||||
|
|
||||||
void SetNull()
|
|
||||||
{
|
|
||||||
nValue = -1;
|
|
||||||
scriptPubKey.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsNull() const
|
|
||||||
{
|
|
||||||
return (nValue == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint256 GetHash() const
|
|
||||||
{
|
|
||||||
return SerializeHash(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator==(const CTxOut& a, const CTxOut& b)
|
|
||||||
{
|
|
||||||
return (a.nValue == b.nValue &&
|
|
||||||
a.scriptPubKey == b.scriptPubKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const CTxOut& a, const CTxOut& b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsDust() const;
|
|
||||||
|
|
||||||
std::string ToString() const
|
|
||||||
{
|
|
||||||
if (scriptPubKey.size() < 6)
|
|
||||||
return "CTxOut(error)";
|
|
||||||
return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() const
|
|
||||||
{
|
|
||||||
printf("%s\n", ToString().c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum GetMinFee_mode
|
enum GetMinFee_mode
|
||||||
{
|
{
|
||||||
@ -461,298 +267,72 @@ enum GetMinFee_mode
|
|||||||
GMF_SEND,
|
GMF_SEND,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The basic transaction that is broadcasted on the network and contained in
|
int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, bool fAllowFree = true, enum GetMinFee_mode mode = GMF_BLOCK);
|
||||||
* blocks. A transaction can contain multiple inputs and outputs.
|
|
||||||
*/
|
|
||||||
class CTransaction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static int64 nMinTxFee;
|
|
||||||
static int64 nMinRelayTxFee;
|
|
||||||
static const int CURRENT_VERSION=1;
|
|
||||||
int nVersion;
|
|
||||||
std::vector<CTxIn> vin;
|
|
||||||
std::vector<CTxOut> vout;
|
|
||||||
unsigned int nLockTime;
|
|
||||||
|
|
||||||
CTransaction()
|
//
|
||||||
{
|
// 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);
|
||||||
};
|
};
|
||||||
|
@ -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 \
|
||||||
|
@ -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 \
|
||||||
|
@ -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 \
|
||||||
|
@ -123,6 +123,7 @@ OBJS= \
|
|||||||
obj/init.o \
|
obj/init.o \
|
||||||
obj/bitcoind.o \
|
obj/bitcoind.o \
|
||||||
obj/keystore.o \
|
obj/keystore.o \
|
||||||
|
obj/core.o \
|
||||||
obj/main.o \
|
obj/main.o \
|
||||||
obj/net.o \
|
obj/net.o \
|
||||||
obj/protocol.o \
|
obj/protocol.o \
|
||||||
|
28
src/net.cpp
28
src/net.cpp
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "init.h"
|
#include "core.h"
|
||||||
#include "addrman.h"
|
#include "addrman.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
@ -68,6 +68,10 @@ CCriticalSection cs_vAddedNodes;
|
|||||||
|
|
||||||
static CSemaphore *semOutbound = NULL;
|
static CSemaphore *semOutbound = NULL;
|
||||||
|
|
||||||
|
// Signals for message handling
|
||||||
|
static CNodeSignals g_signals;
|
||||||
|
CNodeSignals& GetNodeSignals() { return g_signals; }
|
||||||
|
|
||||||
void AddOneShot(string strDest)
|
void AddOneShot(string strDest)
|
||||||
{
|
{
|
||||||
LOCK(cs_vOneShots);
|
LOCK(cs_vOneShots);
|
||||||
@ -79,17 +83,6 @@ unsigned short GetListenPort()
|
|||||||
return (unsigned short)(GetArg("-port", GetDefaultPort()));
|
return (unsigned short)(GetArg("-port", GetDefaultPort()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
|
|
||||||
{
|
|
||||||
// Filter out duplicate requests
|
|
||||||
if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
|
|
||||||
return;
|
|
||||||
pindexLastGetBlocksBegin = pindexBegin;
|
|
||||||
hashLastGetBlocksEnd = hashEnd;
|
|
||||||
|
|
||||||
PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// find 'best' local address for a particular peer
|
// find 'best' local address for a particular peer
|
||||||
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
|
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
|
||||||
{
|
{
|
||||||
@ -1574,11 +1567,6 @@ void static StartSync(const vector<CNode*> &vNodes) {
|
|||||||
CNode *pnodeNewSync = NULL;
|
CNode *pnodeNewSync = NULL;
|
||||||
double dBestScore = 0;
|
double dBestScore = 0;
|
||||||
|
|
||||||
// fImporting and fReindex are accessed out of cs_main here, but only
|
|
||||||
// as an optimization - they are checked again in SendMessages.
|
|
||||||
if (fImporting || fReindex)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Iterate over all nodes
|
// Iterate over all nodes
|
||||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||||
// check preconditions for allowing a sync
|
// check preconditions for allowing a sync
|
||||||
@ -1635,7 +1623,7 @@ void ThreadMessageHandler()
|
|||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
||||||
if (lockRecv)
|
if (lockRecv)
|
||||||
if (!ProcessMessages(pnode))
|
if (!g_signals.ProcessMessages(pnode))
|
||||||
pnode->CloseSocketDisconnect();
|
pnode->CloseSocketDisconnect();
|
||||||
}
|
}
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
@ -1644,7 +1632,7 @@ void ThreadMessageHandler()
|
|||||||
{
|
{
|
||||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||||
if (lockSend)
|
if (lockSend)
|
||||||
SendMessages(pnode, pnode == pnodeTrickle);
|
g_signals.SendMessages(pnode, pnode == pnodeTrickle);
|
||||||
}
|
}
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
}
|
}
|
||||||
@ -1861,9 +1849,7 @@ void StartNode(boost::thread_group& threadGroup)
|
|||||||
bool StopNode()
|
bool StopNode()
|
||||||
{
|
{
|
||||||
printf("StopNode()\n");
|
printf("StopNode()\n");
|
||||||
GenerateBitcoins(false, NULL);
|
|
||||||
MapPort(false);
|
MapPort(false);
|
||||||
nTransactionsUpdated++;
|
|
||||||
if (semOutbound)
|
if (semOutbound)
|
||||||
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
|
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
|
||||||
semOutbound->post();
|
semOutbound->post();
|
||||||
|
15
src/net.h
15
src/net.h
@ -8,6 +8,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <boost/array.hpp>
|
#include <boost/array.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/signals2/signal.hpp>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
@ -22,6 +23,9 @@
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "bloom.h"
|
#include "bloom.h"
|
||||||
|
|
||||||
|
/** The maximum number of entries in an 'inv' protocol message */
|
||||||
|
static const unsigned int MAX_INV_SZ = 50000;
|
||||||
|
|
||||||
class CNode;
|
class CNode;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
extern int nBestHeight;
|
extern int nBestHeight;
|
||||||
@ -45,6 +49,16 @@ void StartNode(boost::thread_group& threadGroup);
|
|||||||
bool StopNode();
|
bool StopNode();
|
||||||
void SocketSendData(CNode *pnode);
|
void SocketSendData(CNode *pnode);
|
||||||
|
|
||||||
|
// Signals for message handling
|
||||||
|
struct CNodeSignals
|
||||||
|
{
|
||||||
|
boost::signals2::signal<bool (CNode*)> ProcessMessages;
|
||||||
|
boost::signals2::signal<bool (CNode*, bool)> SendMessages;
|
||||||
|
};
|
||||||
|
|
||||||
|
CNodeSignals& GetNodeSignals();
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
LOCAL_NONE, // unknown
|
LOCAL_NONE, // unknown
|
||||||
@ -600,7 +614,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
|
|
||||||
bool IsSubscribed(unsigned int nChannel);
|
bool IsSubscribed(unsigned int nChannel);
|
||||||
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
|
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
|
||||||
void CancelSubscribe(unsigned int nChannel);
|
void CancelSubscribe(unsigned int nChannel);
|
||||||
|
@ -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>
|
||||||
|
@ -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>";
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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],
|
||||||
|
@ -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],
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
class CKeyPool;
|
class CKeyPool;
|
||||||
class CAccount;
|
class CAccount;
|
||||||
class CAccountingEntry;
|
class CAccountingEntry;
|
||||||
|
class CWallet;
|
||||||
|
class CWalletTx;
|
||||||
|
|
||||||
/** Error statuses for the wallet database */
|
/** Error statuses for the wallet database */
|
||||||
enum DBErrors
|
enum DBErrors
|
||||||
@ -160,4 +162,6 @@ public:
|
|||||||
static bool Recover(CDBEnv& dbenv, std::string filename);
|
static bool Recover(CDBEnv& dbenv, std::string filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool BackupWallet(const CWallet& wallet, const std::string& strDest);
|
||||||
|
|
||||||
#endif // BITCOIN_WALLETDB_H
|
#endif // BITCOIN_WALLETDB_H
|
||||||
|
Loading…
Reference in New Issue
Block a user