Skip to content

Commit 45e5102

Browse files
committed
Policy: MOVEONLY: 3 functions to policy
- [script/standard.o] IsStandard - [main.o] IsStandardTx - [main.o] AreInputsStandard coming from btc@9238ecb41752e097443d0bc117df35ebd4ac932e
1 parent 2c7da7f commit 45e5102

File tree

9 files changed

+224
-189
lines changed

9 files changed

+224
-189
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ libbitcoin_server_a_SOURCES = \
244244
net.cpp \
245245
noui.cpp \
246246
policy/fees.cpp \
247+
policy/policy.cpp \
247248
pow.cpp \
248249
rest.cpp \
249250
rpc/blockchain.cpp \

src/main.cpp

Lines changed: 0 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -709,159 +709,6 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
709709
return nEvicted;
710710
}
711711

712-
bool IsStandardTx(const CTransaction& tx, std::string& reason)
713-
{
714-
AssertLockHeld(cs_main);
715-
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
716-
reason = "version";
717-
return false;
718-
}
719-
720-
// Treat non-final transactions as non-standard to prevent a specific type
721-
// of double-spend attack, as well as DoS attacks. (if the transaction
722-
// can't be mined, the attacker isn't expending resources broadcasting it)
723-
// Basically we don't want to propagate transactions that can't be included in
724-
// the next block.
725-
//
726-
// However, IsFinalTx() is confusing... Without arguments, it uses
727-
// chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height()
728-
// is set to the value of nHeight in the block. However, when IsFinalTx()
729-
// is called within CBlock::AcceptBlock(), the height of the block *being*
730-
// evaluated is what is used. Thus if we want to know if a transaction can
731-
// be part of the *next* block, we need to call IsFinalTx() with one more
732-
// than chainActive.Height().
733-
//
734-
// Timestamps on the other hand don't get any special treatment, because we
735-
// can't know what timestamp the next block will have, and there aren't
736-
// timestamp applications where it matters.
737-
if (!IsFinalTx(tx, chainActive.Height() + 1)) {
738-
reason = "non-final";
739-
return false;
740-
}
741-
742-
// Extremely large transactions with lots of inputs can cost the network
743-
// almost as much to process as they cost the sender in fees, because
744-
// computing signature hashes is O(ninputs*txsize). Limiting transactions
745-
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
746-
unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION);
747-
unsigned int nMaxSize = tx.ContainsZerocoins() ? MAX_ZEROCOIN_TX_SIZE : MAX_STANDARD_TX_SIZE;
748-
if (sz >= nMaxSize) {
749-
reason = "tx-size";
750-
return false;
751-
}
752-
753-
for (const CTxIn& txin : tx.vin) {
754-
if (txin.IsZerocoinSpend() || txin.IsZerocoinPublicSpend())
755-
continue;
756-
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
757-
// keys. (remember the 520 byte limit on redeemScript size) That works
758-
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
759-
// bytes of scriptSig, which we round off to 1650 bytes for some minor
760-
// future-proofing. That's also enough to spend a 20-of-20
761-
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
762-
// considered standard)
763-
if (txin.scriptSig.size() > 1650) {
764-
reason = "scriptsig-size";
765-
return false;
766-
}
767-
if (!txin.scriptSig.IsPushOnly()) {
768-
reason = "scriptsig-not-pushonly";
769-
return false;
770-
}
771-
}
772-
773-
unsigned int nDataOut = 0;
774-
txnouttype whichType;
775-
for (const CTxOut& txout : tx.vout) {
776-
if (!::IsStandard(txout.scriptPubKey, whichType)) {
777-
reason = "scriptpubkey";
778-
return false;
779-
}
780-
781-
if (whichType == TX_NULL_DATA)
782-
nDataOut++;
783-
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
784-
reason = "bare-multisig";
785-
return false;
786-
} else if (txout.IsDust(::minRelayTxFee)) {
787-
reason = "dust";
788-
return false;
789-
}
790-
}
791-
792-
// only one OP_RETURN txout is permitted
793-
if (nDataOut > 1) {
794-
reason = "multi-op-return";
795-
return false;
796-
}
797-
798-
return true;
799-
}
800-
801-
/**
802-
* Check transaction inputs to mitigate two
803-
* potential denial-of-service attacks:
804-
*
805-
* 1. scriptSigs with extra data stuffed into them,
806-
* not consumed by scriptPubKey (or P2SH script)
807-
* 2. P2SH scripts with a crazy number of expensive
808-
* CHECKSIG/CHECKMULTISIG operations
809-
*/
810-
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
811-
{
812-
if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs())
813-
return true; // coinbase has no inputs and zerocoinspend has a special input
814-
//todo should there be a check for a 'standard' zerocoinspend here?
815-
816-
for (unsigned int i = 0; i < tx.vin.size(); i++) {
817-
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
818-
819-
std::vector<std::vector<unsigned char> > vSolutions;
820-
txnouttype whichType;
821-
// get the scriptPubKey corresponding to this input:
822-
const CScript& prevScript = prev.scriptPubKey;
823-
if (!Solver(prevScript, whichType, vSolutions))
824-
return false;
825-
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
826-
if (nArgsExpected < 0)
827-
return false;
828-
829-
// Transactions with extra stuff in their scriptSigs are
830-
// non-standard. Note that this EvalScript() call will
831-
// be quick, because if there are any operations
832-
// beside "push data" in the scriptSig
833-
// IsStandard() will have already returned false
834-
// and this method isn't called.
835-
std::vector<std::vector<unsigned char> > stack;
836-
if (!EvalScript(stack, tx.vin[i].scriptSig, false, BaseSignatureChecker()))
837-
return false;
838-
839-
if (whichType == TX_SCRIPTHASH) {
840-
if (stack.empty())
841-
return false;
842-
CScript subscript(stack.back().begin(), stack.back().end());
843-
std::vector<std::vector<unsigned char> > vSolutions2;
844-
txnouttype whichType2;
845-
if (Solver(subscript, whichType2, vSolutions2)) {
846-
int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
847-
if (tmpExpected < 0)
848-
return false;
849-
nArgsExpected += tmpExpected;
850-
} else {
851-
// Any other Script with less than 15 sigops OK:
852-
unsigned int sigops = subscript.GetSigOpCount(true);
853-
// ... extra data left on the stack after execution is OK, too:
854-
return (sigops <= MAX_P2SH_SIGOPS);
855-
}
856-
}
857-
858-
if (stack.size() != (unsigned int)nArgsExpected)
859-
return false;
860-
}
861-
862-
return true;
863-
}
864-
865712
int GetInputAge(CTxIn& vin)
866713
{
867714
CCoinsView viewDummy;

src/main.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,6 @@ CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned
267267
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
268268
*/
269269

270-
/**
271-
* Check for standard transaction types
272-
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
273-
* @return True if all inputs (scriptSigs) use only standard transaction forms
274-
*/
275-
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
276-
277270
/**
278271
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
279272
* This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
@@ -298,11 +291,6 @@ bool ValidOutPoint(const COutPoint& out, int nHeight);
298291
*/
299292
bool CheckFinalTx(const CTransaction& tx, int flags = -1);
300293

301-
/** Check for standard transaction types
302-
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
303-
*/
304-
bool IsStandardTx(const CTransaction& tx, std::string& reason);
305-
306294
/**
307295
* Closure representing one script verification
308296
* Note that this stores references to the spending transaction

src/policy/policy.cpp

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2014 The Bitcoin developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic
7+
8+
#include "policy/policy.h"
9+
10+
#include "consensus/tx_verify.h" // for IsFinal()
11+
#include "main.h"
12+
#include "tinyformat.h"
13+
#include "util.h"
14+
#include "utilstrencodings.h"
15+
16+
#include <boost/foreach.hpp>
17+
18+
/**
19+
* Check transaction inputs to mitigate two
20+
* potential denial-of-service attacks:
21+
*
22+
* 1. scriptSigs with extra data stuffed into them,
23+
* not consumed by scriptPubKey (or P2SH script)
24+
* 2. P2SH scripts with a crazy number of expensive
25+
* CHECKSIG/CHECKMULTISIG operations
26+
*
27+
* Check transaction inputs, and make sure any
28+
* pay-to-script-hash transactions are evaluating IsStandard scripts
29+
*
30+
* Why bother? To avoid denial-of-service attacks; an attacker
31+
* can submit a standard HASH... OP_EQUAL transaction,
32+
* which will get accepted into blocks. The redemption
33+
* script can be anything; an attacker could use a very
34+
* expensive-to-check-upon-redemption script like:
35+
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
36+
*/
37+
38+
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
39+
{
40+
std::vector<valtype> vSolutions;
41+
if (!Solver(scriptPubKey, whichType, vSolutions))
42+
return false;
43+
44+
if (whichType == TX_MULTISIG)
45+
{
46+
unsigned char m = vSolutions.front()[0];
47+
unsigned char n = vSolutions.back()[0];
48+
// Support up to x-of-3 multisig txns as standard
49+
if (n < 1 || n > 3)
50+
return false;
51+
if (m < 1 || m > n)
52+
return false;
53+
} else if (whichType == TX_NULL_DATA &&
54+
(!GetBoolArg("-datacarrier", true) || scriptPubKey.size() > nMaxDatacarrierBytes))
55+
return false;
56+
57+
return whichType != TX_NONSTANDARD;
58+
}
59+
60+
bool IsStandardTx(const CTransaction& tx, std::string& reason)
61+
{
62+
AssertLockHeld(cs_main);
63+
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
64+
reason = "version";
65+
return false;
66+
}
67+
68+
// Treat non-final transactions as non-standard to prevent a specific type
69+
// of double-spend attack, as well as DoS attacks. (if the transaction
70+
// can't be mined, the attacker isn't expending resources broadcasting it)
71+
// Basically we don't want to propagate transactions that can't be included in
72+
// the next block.
73+
//
74+
// However, IsFinalTx() is confusing... Without arguments, it uses
75+
// chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height()
76+
// is set to the value of nHeight in the block. However, when IsFinalTx()
77+
// is called within CBlock::AcceptBlock(), the height of the block *being*
78+
// evaluated is what is used. Thus if we want to know if a transaction can
79+
// be part of the *next* block, we need to call IsFinalTx() with one more
80+
// than chainActive.Height().
81+
//
82+
// Timestamps on the other hand don't get any special treatment, because we
83+
// can't know what timestamp the next block will have, and there aren't
84+
// timestamp applications where it matters.
85+
if (!IsFinalTx(tx, chainActive.Height() + 1)) {
86+
reason = "non-final";
87+
return false;
88+
}
89+
90+
// Extremely large transactions with lots of inputs can cost the network
91+
// almost as much to process as they cost the sender in fees, because
92+
// computing signature hashes is O(ninputs*txsize). Limiting transactions
93+
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
94+
unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION);
95+
unsigned int nMaxSize = tx.ContainsZerocoins() ? MAX_ZEROCOIN_TX_SIZE : MAX_STANDARD_TX_SIZE;
96+
if (sz >= nMaxSize) {
97+
reason = "tx-size";
98+
return false;
99+
}
100+
101+
for (const CTxIn& txin : tx.vin) {
102+
if (txin.IsZerocoinSpend() || txin.IsZerocoinPublicSpend())
103+
continue;
104+
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
105+
// keys. (remember the 520 byte limit on redeemScript size) That works
106+
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
107+
// bytes of scriptSig, which we round off to 1650 bytes for some minor
108+
// future-proofing. That's also enough to spend a 20-of-20
109+
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
110+
// considered standard)
111+
if (txin.scriptSig.size() > 1650) {
112+
reason = "scriptsig-size";
113+
return false;
114+
}
115+
if (!txin.scriptSig.IsPushOnly()) {
116+
reason = "scriptsig-not-pushonly";
117+
return false;
118+
}
119+
}
120+
121+
unsigned int nDataOut = 0;
122+
txnouttype whichType;
123+
for (const CTxOut& txout : tx.vout) {
124+
if (!::IsStandard(txout.scriptPubKey, whichType)) {
125+
reason = "scriptpubkey";
126+
return false;
127+
}
128+
129+
if (whichType == TX_NULL_DATA)
130+
nDataOut++;
131+
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
132+
reason = "bare-multisig";
133+
return false;
134+
} else if (txout.IsDust(::minRelayTxFee)) {
135+
reason = "dust";
136+
return false;
137+
}
138+
}
139+
140+
// only one OP_RETURN txout is permitted
141+
if (nDataOut > 1) {
142+
reason = "multi-op-return";
143+
return false;
144+
}
145+
146+
return true;
147+
}
148+
149+
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
150+
{
151+
if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs())
152+
return true; // coinbase has no inputs and zerocoinspend has a special input
153+
//todo should there be a check for a 'standard' zerocoinspend here?
154+
155+
for (unsigned int i = 0; i < tx.vin.size(); i++) {
156+
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
157+
158+
std::vector<std::vector<unsigned char> > vSolutions;
159+
txnouttype whichType;
160+
// get the scriptPubKey corresponding to this input:
161+
const CScript& prevScript = prev.scriptPubKey;
162+
if (!Solver(prevScript, whichType, vSolutions))
163+
return false;
164+
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
165+
if (nArgsExpected < 0)
166+
return false;
167+
168+
// Transactions with extra stuff in their scriptSigs are
169+
// non-standard. Note that this EvalScript() call will
170+
// be quick, because if there are any operations
171+
// beside "push data" in the scriptSig
172+
// IsStandard() will have already returned false
173+
// and this method isn't called.
174+
std::vector<std::vector<unsigned char> > stack;
175+
if (!EvalScript(stack, tx.vin[i].scriptSig, false, BaseSignatureChecker()))
176+
return false;
177+
178+
if (whichType == TX_SCRIPTHASH) {
179+
if (stack.empty())
180+
return false;
181+
CScript subscript(stack.back().begin(), stack.back().end());
182+
std::vector<std::vector<unsigned char> > vSolutions2;
183+
txnouttype whichType2;
184+
if (Solver(subscript, whichType2, vSolutions2)) {
185+
int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
186+
if (tmpExpected < 0)
187+
return false;
188+
nArgsExpected += tmpExpected;
189+
} else {
190+
// Any other Script with less than 15 sigops OK:
191+
unsigned int sigops = subscript.GetSigOpCount(true);
192+
// ... extra data left on the stack after execution is OK, too:
193+
return (sigops <= MAX_P2SH_SIGOPS);
194+
}
195+
}
196+
197+
if (stack.size() != (unsigned int)nArgsExpected)
198+
return false;
199+
}
200+
201+
return true;
202+
}

0 commit comments

Comments
 (0)