mirror of
https://github.com/twisterarmy/twister-core.git
synced 2025-01-25 14:04:27 +00:00
Removed AcceptToMemoryPool method from CTransaction. This method belongs to the mempool instance.
Removed AreInputsStandard from CTransaction, made it a regular function in main. Moved CTransaction::GetOutputFor to CCoinsViewCache. Moved GetLegacySigOpCount and GetP2SHSigOpCount out of CTransaction into regular functions in main. Moved GetValueIn and HaveInputs from CTransaction into CCoinsViewCache. Moved AllowFree, ClientCheckInputs, CheckInputs, UpdateCoins, and CheckTransaction out of CTransaction and into main. Moved IsStandard and IsFinal out of CTransaction and put them in main as IsStandardTx and IsFinalTx. Moved GetValueOut out of CTransaction into main. Moved CTxIn, CTxOut, and CTransaction into core. Added minimum fee parameter to CTxOut::IsDust() temporarily until CTransaction is moved to core.h so that CTxOut needn't know about CTransaction.
This commit is contained in:
parent
788536f175
commit
05df3fc68d
@ -3,4 +3,5 @@
|
|||||||
// 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 "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
|
277
src/core.h
277
src/core.h
@ -8,6 +8,7 @@
|
|||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "script.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -65,4 +66,278 @@ public:
|
|||||||
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
|
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
/** 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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "main.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"
|
||||||
|
276
src/main.cpp
276
src/main.cpp
@ -357,41 +357,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 +383,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 +435,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 +460,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 +489,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 +571,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,23 +597,23 @@ 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;
|
||||||
@ -657,7 +685,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
|
||||||
@ -669,7 +697,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?
|
||||||
@ -694,7 +722,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;
|
||||||
@ -734,7 +762,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
|
||||||
@ -745,14 +773,14 @@ 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
|
||||||
@ -787,7 +815,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());
|
||||||
}
|
}
|
||||||
@ -816,14 +844,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)
|
||||||
{
|
{
|
||||||
@ -936,7 +956,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1299,45 +1319,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));
|
||||||
@ -1346,23 +1351,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;
|
||||||
}
|
}
|
||||||
@ -1382,26 +1387,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
|
||||||
@ -1417,13 +1422,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"));
|
||||||
@ -1436,12 +1441,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());
|
||||||
@ -1449,7 +1454,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();
|
||||||
}
|
}
|
||||||
@ -1464,7 +1469,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());
|
||||||
@ -1644,13 +1648,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)
|
||||||
@ -1658,21 +1662,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);
|
||||||
|
|
||||||
@ -1683,8 +1687,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);
|
||||||
@ -1846,7 +1850,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
|
||||||
@ -2076,7 +2080,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
|
||||||
@ -2096,7 +2100,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"));
|
||||||
@ -2135,7 +2139,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
|
||||||
@ -3488,7 +3492,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);
|
||||||
@ -3511,7 +3515,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);
|
||||||
@ -4194,7 +4198,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;
|
||||||
@ -4249,7 +4253,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)
|
||||||
{
|
{
|
||||||
@ -4285,7 +4289,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;
|
||||||
|
|
||||||
@ -4303,22 +4307,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);
|
||||||
@ -4366,7 +4370,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
|
|||||||
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;
|
||||||
|
406
src/main.h
406
src/main.h
@ -254,155 +254,6 @@ struct CDiskTxPos : public CDiskBlockPos
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 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
|
||||||
{
|
{
|
||||||
GMF_BLOCK,
|
GMF_BLOCK,
|
||||||
@ -412,215 +263,71 @@ enum GetMinFee_mode
|
|||||||
|
|
||||||
int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, bool fAllowFree = true, enum GetMinFee_mode mode = GMF_BLOCK);
|
int64 GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, bool fAllowFree = true, enum GetMinFee_mode mode = GMF_BLOCK);
|
||||||
|
|
||||||
/** The basic transaction that is broadcasted on the network and contained in
|
//
|
||||||
* blocks. A transaction can contain multiple inputs and outputs.
|
// Check transaction inputs, and make sure any
|
||||||
*/
|
// pay-to-script-hash transactions are evaluating IsStandard scripts
|
||||||
class CTransaction
|
//
|
||||||
{
|
// Why bother? To avoid denial-of-service attacks; an attacker
|
||||||
public:
|
// can submit a standard HASH... OP_EQUAL transaction,
|
||||||
static int64 nMinTxFee;
|
// which will get accepted into blocks. The redemption
|
||||||
static int64 nMinRelayTxFee;
|
// script can be anything; an attacker could use a very
|
||||||
static const int CURRENT_VERSION=1;
|
// expensive-to-check-upon-redemption script like:
|
||||||
int nVersion;
|
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
|
||||||
std::vector<CTxIn> vin;
|
//
|
||||||
std::vector<CTxOut> vout;
|
|
||||||
unsigned int nLockTime;
|
|
||||||
|
|
||||||
CTransaction()
|
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
IMPLEMENT_SERIALIZE
|
|
||||||
(
|
|
||||||
READWRITE(this->nVersion);
|
|
||||||
nVersion = this->nVersion;
|
|
||||||
READWRITE(vin);
|
|
||||||
READWRITE(vout);
|
|
||||||
READWRITE(nLockTime);
|
|
||||||
)
|
|
||||||
|
|
||||||
void SetNull()
|
|
||||||
{
|
|
||||||
nVersion = CTransaction::CURRENT_VERSION;
|
|
||||||
vin.clear();
|
|
||||||
vout.clear();
|
|
||||||
nLockTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsNull() const
|
|
||||||
{
|
|
||||||
return (vin.empty() && vout.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint256 GetHash() const
|
|
||||||
{
|
|
||||||
return SerializeHash(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
|
|
||||||
{
|
|
||||||
// Time based nLockTime implemented in 0.1.6
|
|
||||||
if (nLockTime == 0)
|
|
||||||
return true;
|
|
||||||
if (nBlockHeight == 0)
|
|
||||||
nBlockHeight = nBestHeight;
|
|
||||||
if (nBlockTime == 0)
|
|
||||||
nBlockTime = GetAdjustedTime();
|
|
||||||
if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
|
|
||||||
return true;
|
|
||||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
|
||||||
if (!txin.IsFinal())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsNewerThan(const CTransaction& old) const
|
|
||||||
{
|
|
||||||
if (vin.size() != old.vin.size())
|
|
||||||
return false;
|
|
||||||
for (unsigned int i = 0; i < vin.size(); i++)
|
|
||||||
if (vin[i].prevout != old.vin[i].prevout)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool fNewer = false;
|
|
||||||
unsigned int nLowest = std::numeric_limits<unsigned int>::max();
|
|
||||||
for (unsigned int i = 0; i < vin.size(); i++)
|
|
||||||
{
|
|
||||||
if (vin[i].nSequence != old.vin[i].nSequence)
|
|
||||||
{
|
|
||||||
if (vin[i].nSequence <= nLowest)
|
|
||||||
{
|
|
||||||
fNewer = false;
|
|
||||||
nLowest = vin[i].nSequence;
|
|
||||||
}
|
|
||||||
if (old.vin[i].nSequence < nLowest)
|
|
||||||
{
|
|
||||||
fNewer = true;
|
|
||||||
nLowest = old.vin[i].nSequence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fNewer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsCoinBase() const
|
|
||||||
{
|
|
||||||
return (vin.size() == 1 && vin[0].prevout.IsNull());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check for standard transaction types
|
/** Check for standard transaction types
|
||||||
@return True if all outputs (scriptPubKeys) use only standard transaction forms
|
@param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||||
*/
|
|
||||||
bool IsStandard() const;
|
|
||||||
|
|
||||||
/** Check for standard transaction types
|
|
||||||
@param[in] mapInputs Map of previous transactions that have outputs we're spending
|
|
||||||
@return True if all inputs (scriptSigs) use only standard transaction forms
|
@return True if all inputs (scriptSigs) use only standard transaction forms
|
||||||
*/
|
*/
|
||||||
bool AreInputsStandard(CCoinsViewCache& mapInputs) const;
|
bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs);
|
||||||
|
|
||||||
/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
||||||
@return number of sigops this transaction's outputs will produce when spent
|
@return number of sigops this transaction's outputs will produce when spent
|
||||||
*/
|
@see CTransaction::FetchInputs
|
||||||
unsigned int GetLegacySigOpCount() const;
|
*/
|
||||||
|
unsigned int GetLegacySigOpCount(const CTransaction& tx);
|
||||||
|
|
||||||
/** Count ECDSA signature operations in pay-to-script-hash inputs.
|
/** Count ECDSA signature operations in pay-to-script-hash inputs.
|
||||||
|
|
||||||
@param[in] mapInputs Map of previous transactions that have outputs we're spending
|
@param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||||
@return maximum number of sigops required to validate this transaction's inputs
|
@return maximum number of sigops required to validate this transaction's inputs
|
||||||
*/
|
@see CTransaction::FetchInputs
|
||||||
unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const;
|
*/
|
||||||
|
unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs);
|
||||||
/** Amount of bitcoins spent by this transaction.
|
|
||||||
@return sum of all outputs (note: does not include fees)
|
|
||||||
*/
|
|
||||||
int64 GetValueOut() const
|
|
||||||
{
|
|
||||||
int64 nValueOut = 0;
|
|
||||||
BOOST_FOREACH(const CTxOut& txout, vout)
|
|
||||||
{
|
|
||||||
nValueOut += txout.nValue;
|
|
||||||
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
|
|
||||||
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
|
|
||||||
}
|
|
||||||
return nValueOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Amount of bitcoins coming in to this transaction
|
|
||||||
Note that lightweight clients may not know anything besides the hash of previous transactions,
|
|
||||||
so may not be able to calculate this.
|
|
||||||
|
|
||||||
@param[in] mapInputs Map of previous transactions that have outputs we're spending
|
|
||||||
@return Sum of value of all inputs (scriptSigs)
|
|
||||||
*/
|
|
||||||
int64 GetValueIn(CCoinsViewCache& mapInputs) const;
|
|
||||||
|
|
||||||
static bool AllowFree(double dPriority)
|
|
||||||
{
|
|
||||||
// Large (in bytes) low-priority (new, small-coin) transactions
|
|
||||||
// need a fee.
|
|
||||||
return dPriority > COIN * 144 / 250;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
inline bool AllowFree(double dPriority)
|
||||||
{
|
{
|
||||||
std::string str;
|
// Large (in bytes) low-priority (new, small-coin) transactions
|
||||||
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n",
|
// need a fee.
|
||||||
GetHash().ToString().c_str(),
|
return dPriority > COIN * 144 / 250;
|
||||||
nVersion,
|
}
|
||||||
vin.size(),
|
|
||||||
vout.size(),
|
|
||||||
nLockTime);
|
|
||||||
for (unsigned int i = 0; i < vin.size(); i++)
|
|
||||||
str += " " + vin[i].ToString() + "\n";
|
|
||||||
for (unsigned int i = 0; i < vout.size(); i++)
|
|
||||||
str += " " + vout[i].ToString() + "\n";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() const
|
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
|
||||||
{
|
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
|
||||||
printf("%s", ToString().c_str());
|
// instead of being performed inline.
|
||||||
}
|
bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
|
||||||
|
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
|
||||||
|
std::vector<CScriptCheck> *pvChecks = NULL);
|
||||||
|
|
||||||
|
// Apply the effects of this transaction on the UTXO set represented by view
|
||||||
|
bool UpdateCoins(const CTransaction& tx, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash);
|
||||||
|
|
||||||
// Check whether all prevouts of this transaction are present in the UTXO set represented by view
|
// Context-independent validity checks
|
||||||
bool HaveInputs(CCoinsViewCache &view) const;
|
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||||
|
|
||||||
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
|
/** Check for standard transaction types
|
||||||
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
|
@return True if all outputs (scriptPubKeys) use only standard transaction forms
|
||||||
// instead of being performed inline.
|
*/
|
||||||
bool CheckInputs(CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
|
bool IsStandardTx(const CTransaction& tx);
|
||||||
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
|
|
||||||
std::vector<CScriptCheck> *pvChecks = NULL) const;
|
|
||||||
|
|
||||||
// Apply the effects of this transaction on the UTXO set represented by view
|
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0);
|
||||||
void UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
|
|
||||||
|
|
||||||
// Context-independent validity checks
|
/** Amount of bitcoins spent by the transaction.
|
||||||
bool CheckTransaction(CValidationState &state) const;
|
@return sum of all outputs (note: does not include fees)
|
||||||
|
*/
|
||||||
|
int64 GetValueOut(const CTransaction& tx);
|
||||||
|
|
||||||
// Try to accept this transaction into the memory pool
|
|
||||||
bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** wrapper for CTxOut that provides a more compact serialization */
|
/** wrapper for CTxOut that provides a more compact serialization */
|
||||||
class CTxOutCompressor
|
class CTxOutCompressor
|
||||||
@ -2132,6 +1839,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);
|
||||||
};
|
};
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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())
|
||||||
|
@ -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,7 +1276,7 @@ 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 = GetMinFee(wtxNew, 1, fAllowFree, GMF_SEND);
|
int64 nMinFee = GetMinFee(wtxNew, 1, fAllowFree, GMF_SEND);
|
||||||
if (nFeeRet < max(nPayFee, nMinFee))
|
if (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)
|
||||||
|
@ -641,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;
|
||||||
@ -658,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
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user