Browse Source

Get rid of inaccurate ScriptSigArgsExpected

(cherry picked from commit 52b29dca7670c3f6d2ab918c0fff1d17c4e494ad)
0.13
Pieter Wuille 9 years ago committed by MarcoFalke
parent
commit
5d743099b5
  1. 35
      src/policy/policy.cpp
  2. 21
      src/script/standard.cpp
  3. 1
      src/script/standard.h
  4. 9
      src/test/script_P2SH_tests.cpp
  5. 8
      src/test/transaction_tests.cpp

35
src/policy/policy.cpp

@ -132,45 +132,20 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
const CScript& prevScript = prev.scriptPubKey; const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions)) if (!Solver(prevScript, whichType, vSolutions))
return false; return false;
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
if (nArgsExpected < 0)
return false;
// 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
// IsStandardTx() will have already returned false
// and this method isn't called.
std::vector<std::vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
return false;
if (whichType == TX_SCRIPTHASH) if (whichType == TX_SCRIPTHASH)
{ {
std::vector<std::vector<unsigned char> > stack;
// convert the scriptSig into a stack, so we can inspect the redeemScript
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), 0))
return false;
if (stack.empty()) if (stack.empty())
return false; return false;
CScript subscript(stack.back().begin(), stack.back().end()); CScript subscript(stack.back().begin(), stack.back().end());
std::vector<std::vector<unsigned char> > vSolutions2; if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
txnouttype whichType2;
if (Solver(subscript, whichType2, vSolutions2))
{
int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
if (tmpExpected < 0)
return false; return false;
nArgsExpected += tmpExpected;
}
else
{
// Any other Script with less than 15 sigops OK:
unsigned int sigops = subscript.GetSigOpCount(true);
// ... extra data left on the stack after execution is OK, too:
return (sigops <= MAX_P2SH_SIGOPS);
} }
} }
if (stack.size() != (unsigned int)nArgsExpected)
return false;
} }
return true; return true;

21
src/script/standard.cpp

@ -161,27 +161,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
return false; return false;
} }
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
{
switch (t)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
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 ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{ {
vector<valtype> vSolutions; vector<valtype> vSolutions;

1
src/script/standard.h

@ -71,7 +71,6 @@ typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
const char* GetTxnOutputType(txnouttype t); const char* GetTxnOutputType(txnouttype t);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); 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 ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);

9
src/test/script_P2SH_tests.cpp

@ -346,15 +346,6 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
// 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(!::AreInputsStandard(txTo, coins));
txTo.vin[i].scriptSig = t;
}
CMutableTransaction txToNonStd1; CMutableTransaction txToNonStd1;
txToNonStd1.vout.resize(1); txToNonStd1.vout.resize(1);
txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());

8
src/test/transaction_tests.cpp

@ -310,14 +310,6 @@ BOOST_AUTO_TEST_CASE(test_Get)
BOOST_CHECK(AreInputsStandard(t1, coins)); BOOST_CHECK(AreInputsStandard(t1, coins));
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (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:
t1.vin[0].scriptSig << OP_11;
BOOST_CHECK(!AreInputsStandard(t1, coins));
// ... as should not having enough:
t1.vin[0].scriptSig = CScript();
BOOST_CHECK(!AreInputsStandard(t1, coins));
} }
BOOST_AUTO_TEST_CASE(test_IsStandard) BOOST_AUTO_TEST_CASE(test_IsStandard)

Loading…
Cancel
Save