Changeset View
Changeset View
Standalone View
Standalone View
src/test/sighash_tests.cpp
Show First 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | for (int i = 0; i < nRandomTests; i++) { | ||||
CMutableTransaction txTo; | CMutableTransaction txTo; | ||||
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); | RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); | ||||
CScript scriptCode; | CScript scriptCode; | ||||
RandomScript(scriptCode); | RandomScript(scriptCode); | ||||
int nIn = insecure_rand() % txTo.vin.size(); | int nIn = insecure_rand() % txTo.vin.size(); | ||||
uint256 sh, sho; | uint256 sh, sho; | ||||
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); | sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); | ||||
sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0); | sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, CScript()); | ||||
#if defined(PRINT_SIGHASH_JSON) | #if defined(PRINT_SIGHASH_JSON) | ||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | ||||
ss << txTo; | ss << txTo; | ||||
std::cout << "\t[\""; | std::cout << "\t[\""; | ||||
std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; | std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; | ||||
std::cout << HexStr(scriptCode) << "\", "; | std::cout << HexStr(scriptCode) << "\", "; | ||||
std::cout << nIn << ", "; | std::cout << nIn << ", "; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | for (unsigned int idx = 0; idx < tests.size(); idx++) { | ||||
std::vector<uint8_t> raw = ParseHex(raw_script); | std::vector<uint8_t> raw = ParseHex(raw_script); | ||||
scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); | scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); | ||||
} catch (...) { | } catch (...) { | ||||
BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); | BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); | ||||
continue; | continue; | ||||
} | } | ||||
sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0); | sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, CScript()); | ||||
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); | BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); | ||||
} | } | ||||
} | } | ||||
// Check the variance/invariance of different input fields under signature | |||||
// hashing | |||||
BOOST_AUTO_TEST_CASE(sighash_invariance) { | |||||
// tx with 2 inputs | |||||
CMutableTransaction tx1; | |||||
tx1.vin.resize(2); | |||||
tx1.vin[0].prevout = COutPoint(GetRandHash(), insecure_rand()); | |||||
tx1.vin[0].nSequence = insecure_rand(); | |||||
RandomScript(tx1.vin[0].scriptSig); | |||||
tx1.vin[1].prevout = COutPoint(GetRandHash(), insecure_rand()); | |||||
tx1.vin[1].nSequence = insecure_rand(); | |||||
RandomScript(tx1.vin[1].scriptSig); | |||||
CScript pubKey1, pubKey2; | |||||
RandomScript(pubKey1); | |||||
RandomScript(pubKey2); | |||||
// all valid hashtypes | |||||
std::vector<uint8_t> sighashtypes; | |||||
for (int n = SIGHASH_ALL; n <= SIGHASH_SINGLE; n++) { | |||||
sighashtypes.push_back(n | SIGHASH_FORKID); | |||||
sighashtypes.push_back(n | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); | |||||
sighashtypes.push_back(n | SIGHASH_FORKID | SIGHASH_ANYONECANPAY | | |||||
SIGHASH_SPENDANYOUTPUT); | |||||
} | |||||
const uint32_t flags[] = {SCRIPT_ENABLE_SIGHASH_FORKID, | |||||
SCRIPT_ENABLE_SIGHASH_FORKID | | |||||
SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT}; | |||||
// we'll test invariance through these sighashes and flags | |||||
for (uint8_t hashtype : sighashtypes) { | |||||
for (uint32_t flag : flags) { | |||||
bool expectedInvariant; | |||||
uint256 h1, h2; | |||||
CMutableTransaction tx2 = tx1; | |||||
// Amount invariance | |||||
expectedInvariant = (hashtype & SIGHASH_SPENDANYOUTPUT) && | |||||
(flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT); | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 132, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// PubKey invariance | |||||
expectedInvariant = | |||||
!((hashtype & SIGHASH_SPENDANYOUTPUT) && | |||||
(flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)); | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey2, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// THIS prevout.hash | |||||
tx2 = tx1; | |||||
tx2.vin[1].prevout.hash = GetRandHash(); | |||||
expectedInvariant = (hashtype & SIGHASH_SPENDANYOUTPUT) && | |||||
(flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT); | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// THIS prevout.n | |||||
tx2 = tx1; | |||||
tx2.vin[1].prevout.n += 1; | |||||
expectedInvariant = (hashtype & SIGHASH_SPENDANYOUTPUT) && | |||||
(flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT); | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// THIS prevout.sequence | |||||
tx2 = tx1; | |||||
tx2.vin[1].nSequence += 1; | |||||
expectedInvariant = false; | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// OTHER prevout.hash | |||||
tx2 = tx1; | |||||
tx2.vin[0].prevout.hash = GetRandHash(); | |||||
expectedInvariant = | |||||
((hashtype & SIGHASH_SPENDANYOUTPUT) && | |||||
(flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)) || | |||||
(hashtype & SIGHASH_ANYONECANPAY); | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// OTHER prevout.n | |||||
tx2 = tx1; | |||||
tx2.vin[0].prevout.n += 1; | |||||
expectedInvariant = | |||||
((hashtype & SIGHASH_SPENDANYOUTPUT) && | |||||
(flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)) || | |||||
(hashtype & SIGHASH_ANYONECANPAY); | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
// OTHER prevout.sequence | |||||
tx2 = tx1; | |||||
tx2.vin[0].nSequence += 1; | |||||
expectedInvariant = (hashtype & SIGHASH_ANYONECANPAY) || | |||||
(hashtype & 0x1f) == SIGHASH_NONE || | |||||
(hashtype & 0x1f) == SIGHASH_SINGLE; | |||||
h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, | |||||
pubKey1, nullptr, flag); | |||||
BOOST_CHECK((h1 == h2) == expectedInvariant); | |||||
} | |||||
} | |||||
} | |||||
static void TestCheckSignatureEncoding(std::vector<uint8_t> sig, | |||||
uint8_t hashtype, uint32_t flags, | |||||
ScriptError expected_error) { | |||||
sig.back() = hashtype; | |||||
ScriptError err = SCRIPT_ERR_OK; | |||||
const bool result = CheckSignatureEncoding(sig, flags, &err); | |||||
BOOST_CHECK(result == (expected_error == SCRIPT_ERR_OK)); | |||||
BOOST_CHECK_EQUAL(err, expected_error); | |||||
} | |||||
// Check the allowed sighash flags under different verify flags | |||||
BOOST_AUTO_TEST_CASE(sighash_flags_allowed) { | |||||
CKey key; | |||||
std::vector<uint8_t> sig; | |||||
// create a random valid signature | |||||
key.MakeNewKey(false); | |||||
BOOST_CHECK(key.Sign(GetRandHash(), sig, insecure_rand())); | |||||
sig.push_back(SIGHASH_ALL); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL, 0, SCRIPT_ERR_OK); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL, SCRIPT_VERIFY_STRICTENC, | |||||
SCRIPT_ERR_OK); | |||||
// test forkid | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_FORKID, | |||||
SCRIPT_VERIFY_STRICTENC, | |||||
SCRIPT_ERR_ILLEGAL_FORKID); | |||||
TestCheckSignatureEncoding( | |||||
sig, SIGHASH_ALL | SIGHASH_FORKID, | |||||
SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID, SCRIPT_ERR_OK); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL, | |||||
SCRIPT_VERIFY_STRICTENC | | |||||
SCRIPT_ENABLE_SIGHASH_FORKID, | |||||
SCRIPT_ERR_MUST_USE_FORKID); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL, SCRIPT_ENABLE_SIGHASH_FORKID, | |||||
SCRIPT_ERR_OK); // No checks without strictenc | |||||
// test spendanyoutput | |||||
TestCheckSignatureEncoding(sig, SIGHASH_SPENDANYOUTPUT | SIGHASH_SINGLE, | |||||
SCRIPT_VERIFY_STRICTENC, | |||||
SCRIPT_ERR_SPENDANYOUTPUT_NOT_ENABLED); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_SPENDANYOUTPUT | SIGHASH_SINGLE, | |||||
SCRIPT_VERIFY_STRICTENC | | |||||
SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL, | |||||
SCRIPT_VERIFY_STRICTENC | | |||||
SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_ERR_OK); // spend-any-output not mandatory | |||||
// test combination | |||||
TestCheckSignatureEncoding( | |||||
sig, SIGHASH_ALL | SIGHASH_ANYONECANPAY | SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_ERR_OK); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_ANYONECANPAY, | |||||
SCRIPT_VERIFY_STRICTENC | | |||||
SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_ERR_OK); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_VERIFY_STRICTENC | | |||||
SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, | |||||
SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY); | |||||
TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_SPENDANYOUTPUT, 0, | |||||
SCRIPT_ERR_OK); // No checks without strictenc | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |