Browse Source

Make transactions with extra data in their scriptSig's non-standard.

0.8
Gavin Andresen 13 years ago
parent
commit
39f0d96860
  1. 25
      src/main.cpp
  2. 19
      src/script.cpp
  3. 1
      src/script.h
  4. 9
      src/test/script_P2SH_tests.cpp
  5. 24
      src/test/transaction_tests.cpp

25
src/main.cpp

@ -293,18 +293,33 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
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);
// 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) if (whichType == TX_SCRIPTHASH)
{ {
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, vin[i].scriptSig, *this, i, 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());
if (!::IsStandard(subscript)) vector<vector<unsigned char> > vSolutions2;
txnouttype whichType2;
if (!Solver(subscript, whichType2, vSolutions2))
return false; return false;
if (whichType2 == TX_SCRIPTHASH)
return false;
nArgsExpected += ScriptSigArgsExpected(whichType2, vSolutions2);
} }
if (stack.size() != nArgsExpected)
return false;
} }
return true; return true;

19
src/script.cpp

@ -1312,6 +1312,25 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false; 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) bool IsStandard(const CScript& scriptPubKey)
{ {

1
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 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); 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 IsStandard(const CScript& scriptPubKey);
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet); bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet);

9
src/test/script_P2SH_tests.cpp

@ -293,6 +293,15 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
BOOST_CHECK(txTo.AreInputsStandard(mapInputs)); BOOST_CHECK(txTo.AreInputsStandard(mapInputs));
// 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; CTransaction txToNonStd;
txToNonStd.vout.resize(1); txToNonStd.vout.resize(1);
txToNonStd.vout[0].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey()); txToNonStd.vout[0].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey());

24
src/test/transaction_tests.cpp

@ -24,8 +24,9 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// //
// Helper: create two dummy transactions, each with // Helper: create two dummy transactions, each with
// two outputs. The first has 11 and 50 CENT outputs, // two outputs. The first has 11 and 50 CENT outputs
// the second 21 and 22 CENT outputs. // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
// paid to a TX_PUBKEYHASH.
// //
static std::vector<CTransaction> static std::vector<CTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
@ -44,9 +45,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
// Create some dummy input transactions // Create some dummy input transactions
dummyTransactions[0].vout.resize(2); dummyTransactions[0].vout.resize(2);
dummyTransactions[0].vout[0].nValue = 11*CENT; 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].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]); inputsRet[dummyTransactions[0].GetHash()] = make_pair(CTxIndex(), dummyTransactions[0]);
dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout.resize(2);
@ -69,10 +70,13 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vin.resize(3); t1.vin.resize(3);
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t1.vin[0].prevout.n = 1; 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[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].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.resize(2);
t1.vout[0].nValue = 90*CENT; t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1; t1.vout[0].scriptPubKey << OP_1;
@ -80,6 +84,14 @@ BOOST_AUTO_TEST_CASE(test_Get)
BOOST_CHECK(t1.AreInputsStandard(dummyInputs)); BOOST_CHECK(t1.AreInputsStandard(dummyInputs));
BOOST_CHECK_EQUAL(t1.GetSigOpCount(dummyInputs), 3); BOOST_CHECK_EQUAL(t1.GetSigOpCount(dummyInputs), 3);
BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT); 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) BOOST_AUTO_TEST_CASE(test_GetThrow)

Loading…
Cancel
Save