aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.cpp25
-rw-r--r--src/script.cpp19
-rw-r--r--src/script.h1
-rw-r--r--src/test/script_P2SH_tests.cpp9
-rw-r--r--src/test/transaction_tests.cpp24
5 files changed, 67 insertions, 11 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 9e5f743b69..52812187d4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -295,18 +295,33 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
return false;
+ int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
+
+ // Transactions with extra stuff in their scriptSigs are
+ // non-standard. Note that this EvalScript() call will
+ // be quick, because if there are any operations
+ // beside "push data" in the scriptSig the
+ // IsStandard() call returns false
+ vector<vector<unsigned char> > stack;
+ if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
+ return false;
+
if (whichType == TX_SCRIPTHASH)
{
- vector<vector<unsigned char> > stack;
-
- if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
- return false;
if (stack.empty())
return false;
CScript subscript(stack.back().begin(), stack.back().end());
- if (!::IsStandard(subscript))
+ vector<vector<unsigned char> > vSolutions2;
+ txnouttype whichType2;
+ if (!Solver(subscript, whichType2, vSolutions2))
return false;
+ if (whichType2 == TX_SCRIPTHASH)
+ return false;
+ nArgsExpected += ScriptSigArgsExpected(whichType2, vSolutions2);
}
+
+ if (stack.size() != nArgsExpected)
+ return false;
}
return true;
diff --git a/src/script.cpp b/src/script.cpp
index 66962d78b3..c0523855bd 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1312,6 +1312,25 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false;
}
+int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
+{
+ switch (t)
+ {
+ case TX_NONSTANDARD:
+ return -1;
+ case TX_PUBKEY:
+ return 1;
+ case TX_PUBKEYHASH:
+ return 2;
+ case TX_MULTISIG:
+ if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
+ return -1;
+ return vSolutions[0][0] + 1;
+ case TX_SCRIPTHASH:
+ return 1; // doesn't include args needed by the script
+ }
+ return -1;
+}
bool IsStandard(const CScript& scriptPubKey)
{
diff --git a/src/script.h b/src/script.h
index 63f9f9353a..4760b99a9b 100644
--- a/src/script.h
+++ b/src/script.h
@@ -560,6 +560,7 @@ public:
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
bool IsStandard(const CScript& scriptPubKey);
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet);
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index c782e0c6c1..e3899113a3 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -300,6 +300,15 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
BOOST_CHECK(txTo.AreInputsStandard(mapInputs));
BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1);
+ // Make sure adding crap to the scriptSigs makes them non-standard:
+ for (int i = 0; i < 3; i++)
+ {
+ CScript t = txTo.vin[i].scriptSig;
+ txTo.vin[i].scriptSig = (CScript() << 11) + t;
+ BOOST_CHECK(!txTo.AreInputsStandard(mapInputs));
+ txTo.vin[i].scriptSig = t;
+ }
+
CTransaction txToNonStd;
txToNonStd.vout.resize(1);
txToNonStd.vout[0].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey());
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 592fe3f81a..cd4d7eed96 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -24,8 +24,9 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
//
// Helper: create two dummy transactions, each with
-// two outputs. The first has 11 and 50 CENT outputs,
-// the second 21 and 22 CENT outputs.
+// two outputs. The first has 11 and 50 CENT outputs
+// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
+// paid to a TX_PUBKEYHASH.
//
static std::vector<CTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
@@ -44,9 +45,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
// Create some dummy input transactions
dummyTransactions[0].vout.resize(2);
dummyTransactions[0].vout[0].nValue = 11*CENT;
- dummyTransactions[0].vout[0].scriptPubKey.SetBitcoinAddress(key[0].GetPubKey());
+ dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG;
dummyTransactions[0].vout[1].nValue = 50*CENT;
- dummyTransactions[0].vout[1].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey());
+ dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG;
inputsRet[dummyTransactions[0].GetHash()] = make_pair(CTxIndex(), dummyTransactions[0]);
dummyTransactions[1].vout.resize(2);
@@ -69,16 +70,27 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vin.resize(3);
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t1.vin[0].prevout.n = 1;
- t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();;
+ t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
+ t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
t1.vin[1].prevout.n = 0;
- t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();;
+ t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
+ t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
t1.vin[2].prevout.n = 1;
+ t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
t1.vout.resize(2);
t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1;
BOOST_CHECK(t1.AreInputsStandard(dummyInputs));
BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT);
+
+ // Adding extra junk to the scriptSig should make it non-standard:
+ t1.vin[0].scriptSig << OP_11;
+ BOOST_CHECK(!t1.AreInputsStandard(dummyInputs));
+
+ // ... as should not having enough:
+ t1.vin[0].scriptSig = CScript();
+ BOOST_CHECK(!t1.AreInputsStandard(dummyInputs));
}
BOOST_AUTO_TEST_CASE(test_GetThrow)