Skip to content

Commit 1e0bc16

Browse files
barrystyleFuzzbawls
authored andcommitted
Move transaction checks out to consensus/tx_verify.cpp.
1 parent ca912fc commit 1e0bc16

File tree

11 files changed

+218
-176
lines changed

11 files changed

+218
-176
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ set(COMMON_SOURCES
453453
./src/coins.cpp
454454
./src/compressor.cpp
455455
./src/consensus/merkle.cpp
456+
./src/consensus/tx_verify.cpp
456457
./src/primitives/block.cpp
457458
./src/zpiv/deterministicmint.cpp
458459
./src/primitives/transaction.cpp

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ BITCOIN_CORE_H = \
102102
consensus/consensus.h \
103103
consensus/merkle.h \
104104
consensus/validation.h \
105+
consensus/tx_verify.h \
105106
primitives/block.h \
106107
primitives/transaction.h \
107108
core_io.h \
@@ -211,6 +212,7 @@ libbitcoin_server_a_SOURCES = \
211212
blocksignature.cpp \
212213
chain.cpp \
213214
checkpoints.cpp \
215+
consensus/tx_verify.cpp \
214216
httprpc.cpp \
215217
httpserver.cpp \
216218
init.cpp \

src/consensus/tx_verify.cpp

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright (c) 2017-2017 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "tx_verify.h"
6+
7+
#include "consensus/consensus.h"
8+
#include "main.h"
9+
#include "script/interpreter.h"
10+
11+
bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime)
12+
{
13+
AssertLockHeld(cs_main);
14+
// Time based nLockTime implemented in 0.1.6
15+
if (tx.nLockTime == 0)
16+
return true;
17+
if (nBlockHeight == 0)
18+
nBlockHeight = chainActive.Height();
19+
if (nBlockTime == 0)
20+
nBlockTime = GetAdjustedTime();
21+
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
22+
return true;
23+
for (const CTxIn& txin : tx.vin)
24+
if (!txin.IsFinal())
25+
return false;
26+
return true;
27+
}
28+
29+
unsigned int GetLegacySigOpCount(const CTransaction& tx)
30+
{
31+
unsigned int nSigOps = 0;
32+
for (const CTxIn& txin : tx.vin) {
33+
nSigOps += txin.scriptSig.GetSigOpCount(false);
34+
}
35+
for (const CTxOut& txout : tx.vout) {
36+
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
37+
}
38+
return nSigOps;
39+
}
40+
41+
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
42+
{
43+
if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs())
44+
// a tx containing a zc spend can have only zc inputs
45+
return 0;
46+
47+
unsigned int nSigOps = 0;
48+
for (unsigned int i = 0; i < tx.vin.size(); i++) {
49+
const CTxOut& prevout = inputs.GetOutputFor(tx.vin[i]);
50+
if (prevout.scriptPubKey.IsPayToScriptHash())
51+
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
52+
}
53+
return nSigOps;
54+
}
55+
56+
bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fRejectBadUTXO, CValidationState& state, bool fFakeSerialAttack, bool fColdStakingActive)
57+
{
58+
// Basic checks that don't depend on any context
59+
if (tx.vin.empty())
60+
return state.DoS(10, error("CheckTransaction() : vin empty"),
61+
REJECT_INVALID, "bad-txns-vin-empty");
62+
if (tx.vout.empty())
63+
return state.DoS(10, error("CheckTransaction() : vout empty"),
64+
REJECT_INVALID, "bad-txns-vout-empty");
65+
66+
// Size limits
67+
unsigned int nMaxSize = MAX_ZEROCOIN_TX_SIZE;
68+
69+
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > nMaxSize)
70+
return state.DoS(100, error("CheckTransaction() : size limits failed"),
71+
REJECT_INVALID, "bad-txns-oversize");
72+
73+
const CAmount minColdStakingAmount = Params().GetMinColdStakingAmount();
74+
75+
// Check for negative or overflow output values
76+
CAmount nValueOut = 0;
77+
for (const CTxOut& txout : tx.vout) {
78+
if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake())
79+
return state.DoS(100, error("CheckTransaction(): txout empty for user transaction"));
80+
if (txout.nValue < 0)
81+
return state.DoS(100, error("CheckTransaction() : txout.nValue negative"),
82+
REJECT_INVALID, "bad-txns-vout-negative");
83+
if (txout.nValue > MAX_MONEY_OUT)
84+
return state.DoS(100, error("CheckTransaction() : txout.nValue too high"),
85+
REJECT_INVALID, "bad-txns-vout-toolarge");
86+
nValueOut += txout.nValue;
87+
if (!MoneyRange(nValueOut))
88+
return state.DoS(100, error("CheckTransaction() : txout total out of range"),
89+
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
90+
if (fZerocoinActive && txout.IsZerocoinMint()) {
91+
if(!CheckZerocoinMint(tx.GetHash(), txout, state, true))
92+
return state.DoS(100, error("CheckTransaction() : invalid zerocoin mint"));
93+
}
94+
// check cold staking enforcement (for delegations) and value out
95+
if (txout.scriptPubKey.IsPayToColdStaking()) {
96+
if (!fColdStakingActive)
97+
return state.DoS(10, error("%s: cold staking not active", __func__), REJECT_INVALID, "bad-txns-cold-stake");
98+
if (txout.nValue < minColdStakingAmount)
99+
return state.DoS(100, error("%s: dust amount (%d) not allowed for cold staking. Min amount: %d",
100+
__func__, txout.nValue, minColdStakingAmount), REJECT_INVALID, "bad-txns-cold-stake");
101+
}
102+
}
103+
104+
std::set<COutPoint> vInOutPoints;
105+
std::set<CBigNum> vZerocoinSpendSerials;
106+
int nZCSpendCount = 0;
107+
108+
for (const CTxIn& txin : tx.vin) {
109+
// Check for duplicate inputs
110+
if (vInOutPoints.count(txin.prevout))
111+
return state.DoS(100, error("CheckTransaction() : duplicate inputs"), REJECT_INVALID, "bad-txns-inputs-duplicate");
112+
113+
//duplicate zcspend serials are checked in CheckZerocoinSpend()
114+
if (!txin.IsZerocoinSpend()) {
115+
vInOutPoints.insert(txin.prevout);
116+
} else if (!txin.IsZerocoinPublicSpend()) {
117+
nZCSpendCount++;
118+
}
119+
}
120+
121+
if (fZerocoinActive) {
122+
if (nZCSpendCount > Params().Zerocoin_MaxSpendsPerTransaction())
123+
return state.DoS(100, error("CheckTransaction() : there are more zerocoin spends than are allowed in one transaction"));
124+
125+
//require that a zerocoinspend only has inputs that are zerocoins
126+
if (tx.HasZerocoinSpendInputs()) {
127+
for (const CTxIn& in : tx.vin) {
128+
if (!in.IsZerocoinSpend() && !in.IsZerocoinPublicSpend())
129+
return state.DoS(100,
130+
error("CheckTransaction() : zerocoinspend contains inputs that are not zerocoins"));
131+
}
132+
133+
// Do not require signature verification if this is initial sync and a block over 24 hours old
134+
bool fVerifySignature = !IsInitialBlockDownload() && (GetTime() - chainActive.Tip()->GetBlockTime() < (60*60*24));
135+
if (!CheckZerocoinSpend(tx, fVerifySignature, state, fFakeSerialAttack))
136+
return state.DoS(100, error("CheckTransaction() : invalid zerocoin spend"));
137+
}
138+
}
139+
140+
if (tx.IsCoinBase()) {
141+
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 150)
142+
return state.DoS(100, error("CheckTransaction() : coinbase script size=%d", tx.vin[0].scriptSig.size()),
143+
REJECT_INVALID, "bad-cb-length");
144+
} else if (fZerocoinActive && tx.HasZerocoinSpendInputs()) {
145+
if (tx.vin.size() < 1)
146+
return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has less than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend");
147+
if (tx.HasZerocoinPublicSpendInputs()) {
148+
// tx has public zerocoin spend inputs
149+
if(static_cast<int>(tx.vin.size()) > Params().Zerocoin_MaxPublicSpendsPerTransaction())
150+
return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend");
151+
} else {
152+
// tx has regular zerocoin spend inputs
153+
if(static_cast<int>(tx.vin.size()) > Params().Zerocoin_MaxSpendsPerTransaction())
154+
return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend");
155+
}
156+
157+
} else {
158+
for (const CTxIn& txin : tx.vin)
159+
if (txin.prevout.IsNull() && (fZerocoinActive && !txin.IsZerocoinSpend()))
160+
return state.DoS(10, error("CheckTransaction() : prevout is null"),
161+
REJECT_INVALID, "bad-txns-prevout-null");
162+
}
163+
164+
return true;
165+
}

src/consensus/tx_verify.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2017-2017 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_CONSENSUS_TX_VERIFY_H
6+
#define BITCOIN_CONSENSUS_TX_VERIFY_H
7+
8+
#include <stdint.h>
9+
#include <vector>
10+
11+
class CBlockIndex;
12+
class CCoinsViewCache;
13+
class CTransaction;
14+
class CValidationState;
15+
16+
/** Transaction validation functions */
17+
18+
/** Context-independent validity checks */
19+
bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fRejectBadUTXO, CValidationState& state, bool fFakeSerialAttack = false, bool fColdStakingActive=false);
20+
21+
/**
22+
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
23+
* @return number of sigops this transaction's outputs will produce when spent
24+
* @see CTransaction::FetchInputs
25+
*/
26+
unsigned int GetLegacySigOpCount(const CTransaction& tx);
27+
28+
/**
29+
* Count ECDSA signature operations in pay-to-script-hash inputs.
30+
*
31+
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
32+
* @return maximum number of sigops required to validate this transaction's inputs
33+
* @see CTransaction::FetchInputs
34+
*/
35+
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
36+
37+
/**
38+
* Check if transaction is final and can be included in a block with the
39+
* specified height and time. Consensus critical.
40+
*/
41+
bool IsFinalTx(const CTransaction& tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
42+
43+
#endif // BITCOIN_CONSENSUS_TX_VERIFY_H

0 commit comments

Comments
 (0)