Changeset View
Changeset View
Standalone View
Standalone View
src/test/script_P2SH_tests.cpp
Show All 30 Lines | static bool Verify(const CScript &scriptSig, const CScript &scriptPubKey, | ||||
txFrom.vout[0].scriptPubKey = scriptPubKey; | txFrom.vout[0].scriptPubKey = scriptPubKey; | ||||
CMutableTransaction txTo; | CMutableTransaction txTo; | ||||
txTo.vin.resize(1); | txTo.vin.resize(1); | ||||
txTo.vout.resize(1); | txTo.vout.resize(1); | ||||
txTo.vin[0].prevout.n = 0; | txTo.vin[0].prevout.n = 0; | ||||
txTo.vin[0].prevout.hash = txFrom.GetId(); | txTo.vin[0].prevout.hash = txFrom.GetId(); | ||||
txTo.vin[0].scriptSig = scriptSig; | txTo.vin[0].scriptSig = scriptSig; | ||||
txTo.vout[0].nValue = 1; | txTo.vout[0].nValue = Amount(1); | ||||
return VerifyScript(scriptSig, scriptPubKey, | return VerifyScript( | ||||
scriptSig, scriptPubKey, | |||||
(fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE) | | (fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE) | | ||||
SCRIPT_ENABLE_SIGHASH_FORKID, | SCRIPT_ENABLE_SIGHASH_FORKID, | ||||
MutableTransactionSignatureChecker( | MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), | ||||
&txTo, 0, txFrom.vout[0].nValue.GetSatoshis()), | |||||
&err); | &err); | ||||
} | } | ||||
BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup) | BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup) | ||||
BOOST_AUTO_TEST_CASE(sign) { | BOOST_AUTO_TEST_CASE(sign) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Pay-to-script-hash looks like this: | // Pay-to-script-hash looks like this: | ||||
// scriptSig: <sig> <sig...> <serialized_script> | // scriptSig: <sig> <sig...> <serialized_script> | ||||
Show All 21 Lines | for (int i = 0; i < 4; i++) { | ||||
evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); | evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); | ||||
} | } | ||||
CMutableTransaction txFrom; // Funding transaction: | CMutableTransaction txFrom; // Funding transaction: | ||||
std::string reason; | std::string reason; | ||||
txFrom.vout.resize(8); | txFrom.vout.resize(8); | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
txFrom.vout[i].scriptPubKey = evalScripts[i]; | txFrom.vout[i].scriptPubKey = evalScripts[i]; | ||||
txFrom.vout[i].nValue = COIN.GetSatoshis(); | txFrom.vout[i].nValue = COIN; | ||||
txFrom.vout[i + 4].scriptPubKey = standardScripts[i]; | txFrom.vout[i + 4].scriptPubKey = standardScripts[i]; | ||||
txFrom.vout[i + 4].nValue = COIN.GetSatoshis(); | txFrom.vout[i + 4].nValue = COIN; | ||||
} | } | ||||
BOOST_CHECK(IsStandardTx(txFrom, reason)); | BOOST_CHECK(IsStandardTx(txFrom, reason)); | ||||
CMutableTransaction txTo[8]; // Spending transactions | CMutableTransaction txTo[8]; // Spending transactions | ||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
txTo[i].vin.resize(1); | txTo[i].vin.resize(1); | ||||
txTo[i].vout.resize(1); | txTo[i].vout.resize(1); | ||||
txTo[i].vin[0].prevout.n = i; | txTo[i].vin[0].prevout.n = i; | ||||
txTo[i].vin[0].prevout.hash = txFrom.GetId(); | txTo[i].vin[0].prevout.hash = txFrom.GetId(); | ||||
txTo[i].vout[0].nValue = 1; | txTo[i].vout[0].nValue = Amount(1); | ||||
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), | BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), | ||||
strprintf("IsMine %d", i)); | strprintf("IsMine %d", i)); | ||||
} | } | ||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, | BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, | ||||
SIGHASH_ALL | SIGHASH_FORKID), | SIGHASH_ALL | SIGHASH_FORKID), | ||||
strprintf("SignSignature %d", i)); | strprintf("SignSignature %d", i)); | ||||
} | } | ||||
// All of the above should be OK, and the txTos have valid signatures | // All of the above should be OK, and the txTos have valid signatures | ||||
// Check to make sure signature verification fails if we use the wrong | // Check to make sure signature verification fails if we use the wrong | ||||
// ScriptSig: | // ScriptSig: | ||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
PrecomputedTransactionData txdata(txTo[i]); | PrecomputedTransactionData txdata(txTo[i]); | ||||
for (int j = 0; j < 8; j++) { | for (int j = 0; j < 8; j++) { | ||||
CScript sigSave = txTo[i].vin[0].scriptSig; | CScript sigSave = txTo[i].vin[0].scriptSig; | ||||
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; | txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; | ||||
const CTxOut &output = txFrom.vout[txTo[i].vin[0].prevout.n]; | const CTxOut &output = txFrom.vout[txTo[i].vin[0].prevout.n]; | ||||
bool sigOK = CScriptCheck( | bool sigOK = | ||||
output.scriptPubKey, output.nValue.GetSatoshis(), txTo[i], 0, | CScriptCheck(output.scriptPubKey, output.nValue, txTo[i], 0, | ||||
SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | | ||||
SCRIPT_ENABLE_SIGHASH_FORKID, | SCRIPT_ENABLE_SIGHASH_FORKID, | ||||
false, txdata)(); | false, txdata)(); | ||||
if (i == j) { | if (i == j) { | ||||
BOOST_CHECK_MESSAGE(sigOK, | BOOST_CHECK_MESSAGE(sigOK, | ||||
strprintf("VerifySignature %d %d", i, j)); | strprintf("VerifySignature %d %d", i, j)); | ||||
} else { | } else { | ||||
BOOST_CHECK_MESSAGE(!sigOK, | BOOST_CHECK_MESSAGE(!sigOK, | ||||
strprintf("VerifySignature %d %d", i, j)); | strprintf("VerifySignature %d %d", i, j)); | ||||
} | } | ||||
txTo[i].vin[0].scriptSig = sigSave; | txTo[i].vin[0].scriptSig = sigSave; | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(set) { | ||||
} | } | ||||
// Funding transaction: | // Funding transaction: | ||||
CMutableTransaction txFrom; | CMutableTransaction txFrom; | ||||
std::string reason; | std::string reason; | ||||
txFrom.vout.resize(4); | txFrom.vout.resize(4); | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
txFrom.vout[i].scriptPubKey = outer[i]; | txFrom.vout[i].scriptPubKey = outer[i]; | ||||
txFrom.vout[i].nValue = CENT.GetSatoshis(); | txFrom.vout[i].nValue = CENT; | ||||
} | } | ||||
BOOST_CHECK(IsStandardTx(txFrom, reason)); | BOOST_CHECK(IsStandardTx(txFrom, reason)); | ||||
// Spending transactions | // Spending transactions | ||||
CMutableTransaction txTo[4]; | CMutableTransaction txTo[4]; | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
txTo[i].vin.resize(1); | txTo[i].vin.resize(1); | ||||
txTo[i].vout.resize(1); | txTo[i].vout.resize(1); | ||||
txTo[i].vin[0].prevout.n = i; | txTo[i].vin[0].prevout.n = i; | ||||
txTo[i].vin[0].prevout.hash = txFrom.GetId(); | txTo[i].vin[0].prevout.hash = txFrom.GetId(); | ||||
txTo[i].vout[0].nValue = 1 * CENT.GetSatoshis(); | txTo[i].vout[0].nValue = 1 * CENT; | ||||
txTo[i].vout[0].scriptPubKey = inner[i]; | txTo[i].vout[0].scriptPubKey = inner[i]; | ||||
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), | BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), | ||||
strprintf("IsMine %d", i)); | strprintf("IsMine %d", i)); | ||||
} | } | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, | BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, | ||||
SIGHASH_ALL | SIGHASH_FORKID), | SIGHASH_ALL | SIGHASH_FORKID), | ||||
strprintf("SignSignature %d", i)); | strprintf("SignSignature %d", i)); | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(AreInputsStandard) { | ||||
// First three are standard: | // First three are standard: | ||||
CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); | CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); | ||||
keystore.AddCScript(pay1); | keystore.AddCScript(pay1); | ||||
CScript pay1of3 = GetScriptForMultisig(1, keys); | CScript pay1of3 = GetScriptForMultisig(1, keys); | ||||
// P2SH (OP_CHECKSIG) | // P2SH (OP_CHECKSIG) | ||||
txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); | txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); | ||||
txFrom.vout[0].nValue = 1000; | txFrom.vout[0].nValue = Amount(1000); | ||||
// ordinary OP_CHECKSIG | // ordinary OP_CHECKSIG | ||||
txFrom.vout[1].scriptPubKey = pay1; | txFrom.vout[1].scriptPubKey = pay1; | ||||
txFrom.vout[1].nValue = 2000; | txFrom.vout[1].nValue = Amount(2000); | ||||
// ordinary OP_CHECKMULTISIG | // ordinary OP_CHECKMULTISIG | ||||
txFrom.vout[2].scriptPubKey = pay1of3; | txFrom.vout[2].scriptPubKey = pay1of3; | ||||
txFrom.vout[2].nValue = 3000; | txFrom.vout[2].nValue = Amount(3000); | ||||
// vout[3] is complicated 1-of-3 AND 2-of-3 | // vout[3] is complicated 1-of-3 AND 2-of-3 | ||||
// ... that is OK if wrapped in P2SH: | // ... that is OK if wrapped in P2SH: | ||||
CScript oneAndTwo; | CScript oneAndTwo; | ||||
oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) | oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) | ||||
<< ToByteVector(key[1].GetPubKey()) | << ToByteVector(key[1].GetPubKey()) | ||||
<< ToByteVector(key[2].GetPubKey()); | << ToByteVector(key[2].GetPubKey()); | ||||
oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY; | oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY; | ||||
oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) | oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) | ||||
<< ToByteVector(key[4].GetPubKey()) | << ToByteVector(key[4].GetPubKey()) | ||||
<< ToByteVector(key[5].GetPubKey()); | << ToByteVector(key[5].GetPubKey()); | ||||
oneAndTwo << OP_3 << OP_CHECKMULTISIG; | oneAndTwo << OP_3 << OP_CHECKMULTISIG; | ||||
keystore.AddCScript(oneAndTwo); | keystore.AddCScript(oneAndTwo); | ||||
txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); | txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); | ||||
txFrom.vout[3].nValue = 4000; | txFrom.vout[3].nValue = Amount(4000); | ||||
// vout[4] is max sigops: | // vout[4] is max sigops: | ||||
CScript fifteenSigops; | CScript fifteenSigops; | ||||
fifteenSigops << OP_1; | fifteenSigops << OP_1; | ||||
for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++) | for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++) | ||||
fifteenSigops << ToByteVector(key[i % 3].GetPubKey()); | fifteenSigops << ToByteVector(key[i % 3].GetPubKey()); | ||||
fifteenSigops << OP_15 << OP_CHECKMULTISIG; | fifteenSigops << OP_15 << OP_CHECKMULTISIG; | ||||
keystore.AddCScript(fifteenSigops); | keystore.AddCScript(fifteenSigops); | ||||
txFrom.vout[4].scriptPubKey = | txFrom.vout[4].scriptPubKey = | ||||
GetScriptForDestination(CScriptID(fifteenSigops)); | GetScriptForDestination(CScriptID(fifteenSigops)); | ||||
txFrom.vout[4].nValue = 5000; | txFrom.vout[4].nValue = Amount(5000); | ||||
// vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS | // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS | ||||
CScript sixteenSigops; | CScript sixteenSigops; | ||||
sixteenSigops << OP_16 << OP_CHECKMULTISIG; | sixteenSigops << OP_16 << OP_CHECKMULTISIG; | ||||
keystore.AddCScript(sixteenSigops); | keystore.AddCScript(sixteenSigops); | ||||
txFrom.vout[5].scriptPubKey = | txFrom.vout[5].scriptPubKey = | ||||
GetScriptForDestination(CScriptID(fifteenSigops)); | GetScriptForDestination(CScriptID(fifteenSigops)); | ||||
txFrom.vout[5].nValue = 5000; | txFrom.vout[5].nValue = Amount(5000); | ||||
CScript twentySigops; | CScript twentySigops; | ||||
twentySigops << OP_CHECKMULTISIG; | twentySigops << OP_CHECKMULTISIG; | ||||
keystore.AddCScript(twentySigops); | keystore.AddCScript(twentySigops); | ||||
txFrom.vout[6].scriptPubKey = | txFrom.vout[6].scriptPubKey = | ||||
GetScriptForDestination(CScriptID(twentySigops)); | GetScriptForDestination(CScriptID(twentySigops)); | ||||
txFrom.vout[6].nValue = 6000; | txFrom.vout[6].nValue = Amount(6000); | ||||
AddCoins(coins, txFrom, 0); | AddCoins(coins, txFrom, 0); | ||||
CMutableTransaction txTo; | CMutableTransaction txTo; | ||||
txTo.vout.resize(1); | txTo.vout.resize(1); | ||||
txTo.vout[0].scriptPubKey = | txTo.vout[0].scriptPubKey = | ||||
GetScriptForDestination(key[1].GetPubKey().GetID()); | GetScriptForDestination(key[1].GetPubKey().GetID()); | ||||
Show All 20 Lines | BOOST_AUTO_TEST_CASE(AreInputsStandard) { | ||||
BOOST_CHECK(::AreInputsStandard(txTo, coins)); | BOOST_CHECK(::AreInputsStandard(txTo, coins)); | ||||
// 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); | ||||
CMutableTransaction txToNonStd1; | CMutableTransaction txToNonStd1; | ||||
txToNonStd1.vout.resize(1); | txToNonStd1.vout.resize(1); | ||||
txToNonStd1.vout[0].scriptPubKey = | txToNonStd1.vout[0].scriptPubKey = | ||||
GetScriptForDestination(key[1].GetPubKey().GetID()); | GetScriptForDestination(key[1].GetPubKey().GetID()); | ||||
txToNonStd1.vout[0].nValue = 1000; | txToNonStd1.vout[0].nValue = Amount(1000); | ||||
txToNonStd1.vin.resize(1); | txToNonStd1.vin.resize(1); | ||||
txToNonStd1.vin[0].prevout.n = 5; | txToNonStd1.vin[0].prevout.n = 5; | ||||
txToNonStd1.vin[0].prevout.hash = txFrom.GetId(); | txToNonStd1.vin[0].prevout.hash = txFrom.GetId(); | ||||
txToNonStd1.vin[0].scriptSig | txToNonStd1.vin[0].scriptSig | ||||
<< std::vector<uint8_t>(sixteenSigops.begin(), sixteenSigops.end()); | << std::vector<uint8_t>(sixteenSigops.begin(), sixteenSigops.end()); | ||||
BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); | BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); | ||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); | BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); | ||||
CMutableTransaction txToNonStd2; | CMutableTransaction txToNonStd2; | ||||
txToNonStd2.vout.resize(1); | txToNonStd2.vout.resize(1); | ||||
txToNonStd2.vout[0].scriptPubKey = | txToNonStd2.vout[0].scriptPubKey = | ||||
GetScriptForDestination(key[1].GetPubKey().GetID()); | GetScriptForDestination(key[1].GetPubKey().GetID()); | ||||
txToNonStd2.vout[0].nValue = 1000; | txToNonStd2.vout[0].nValue = Amount(1000); | ||||
txToNonStd2.vin.resize(1); | txToNonStd2.vin.resize(1); | ||||
txToNonStd2.vin[0].prevout.n = 6; | txToNonStd2.vin[0].prevout.n = 6; | ||||
txToNonStd2.vin[0].prevout.hash = txFrom.GetId(); | txToNonStd2.vin[0].prevout.hash = txFrom.GetId(); | ||||
txToNonStd2.vin[0].scriptSig | txToNonStd2.vin[0].scriptSig | ||||
<< std::vector<uint8_t>(twentySigops.begin(), twentySigops.end()); | << std::vector<uint8_t>(twentySigops.begin(), twentySigops.end()); | ||||
BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); | BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); | ||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); | BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |