Changeset View
Changeset View
Standalone View
Standalone View
src/test/transaction_tests.cpp
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | for (size_t idx = 0; idx < tests.size(); idx++) { | ||||
std::string strTest = test.write(); | std::string strTest = test.write(); | ||||
if (test[0].isArray()) { | if (test[0].isArray()) { | ||||
if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { | if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { | ||||
BOOST_ERROR("Bad test: " << strTest); | BOOST_ERROR("Bad test: " << strTest); | ||||
continue; | continue; | ||||
} | } | ||||
std::map<COutPoint, CScript> mapprevOutScriptPubKeys; | std::map<COutPoint, CScript> mapprevOutScriptPubKeys; | ||||
std::map<COutPoint, int64_t> mapprevOutValues; | std::map<COutPoint, Amount> mapprevOutValues; | ||||
UniValue inputs = test[0].get_array(); | UniValue inputs = test[0].get_array(); | ||||
bool fValid = true; | bool fValid = true; | ||||
for (size_t inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { | for (size_t inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { | ||||
const UniValue &input = inputs[inpIdx]; | const UniValue &input = inputs[inpIdx]; | ||||
if (!input.isArray()) { | if (!input.isArray()) { | ||||
fValid = false; | fValid = false; | ||||
break; | break; | ||||
} | } | ||||
UniValue vinput = input.get_array(); | UniValue vinput = input.get_array(); | ||||
if (vinput.size() < 3 || vinput.size() > 4) { | if (vinput.size() < 3 || vinput.size() > 4) { | ||||
fValid = false; | fValid = false; | ||||
break; | break; | ||||
} | } | ||||
COutPoint outpoint(uint256S(vinput[0].get_str()), | COutPoint outpoint(uint256S(vinput[0].get_str()), | ||||
vinput[1].get_int()); | vinput[1].get_int()); | ||||
mapprevOutScriptPubKeys[outpoint] = | mapprevOutScriptPubKeys[outpoint] = | ||||
ParseScript(vinput[2].get_str()); | ParseScript(vinput[2].get_str()); | ||||
if (vinput.size() >= 4) { | if (vinput.size() >= 4) { | ||||
mapprevOutValues[outpoint] = vinput[3].get_int64(); | mapprevOutValues[outpoint] = Amount(vinput[3].get_int64()); | ||||
} | } | ||||
} | } | ||||
if (!fValid) { | if (!fValid) { | ||||
BOOST_ERROR("Bad test: " << strTest); | BOOST_ERROR("Bad test: " << strTest); | ||||
continue; | continue; | ||||
} | } | ||||
std::string transaction = test[1].get_str(); | std::string transaction = test[1].get_str(); | ||||
Show All 12 Lines | for (size_t idx = 0; idx < tests.size(); idx++) { | ||||
for (size_t i = 0; i < tx.vin.size(); i++) { | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) { | if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) { | ||||
BOOST_ERROR("Bad test: " << strTest); | BOOST_ERROR("Bad test: " << strTest); | ||||
break; | break; | ||||
} | } | ||||
Amount amount(0); | Amount amount(0); | ||||
if (mapprevOutValues.count(tx.vin[i].prevout)) { | if (mapprevOutValues.count(tx.vin[i].prevout)) { | ||||
amount = mapprevOutValues[tx.vin[i].prevout]; | amount = Amount(mapprevOutValues[tx.vin[i].prevout]); | ||||
} | } | ||||
uint32_t verify_flags = ParseScriptFlags(test[2].get_str()); | uint32_t verify_flags = ParseScriptFlags(test[2].get_str()); | ||||
BOOST_CHECK_MESSAGE( | BOOST_CHECK_MESSAGE( | ||||
VerifyScript(tx.vin[i].scriptSig, | VerifyScript(tx.vin[i].scriptSig, | ||||
mapprevOutScriptPubKeys[tx.vin[i].prevout], | mapprevOutScriptPubKeys[tx.vin[i].prevout], | ||||
verify_flags, TransactionSignatureChecker( | verify_flags, TransactionSignatureChecker( | ||||
&tx, i, amount, txdata), | &tx, i, amount, txdata), | ||||
Show All 26 Lines | for (size_t idx = 0; idx < tests.size(); idx++) { | ||||
std::string strTest = test.write(); | std::string strTest = test.write(); | ||||
if (test[0].isArray()) { | if (test[0].isArray()) { | ||||
if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { | if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { | ||||
BOOST_ERROR("Bad test: " << strTest); | BOOST_ERROR("Bad test: " << strTest); | ||||
continue; | continue; | ||||
} | } | ||||
std::map<COutPoint, CScript> mapprevOutScriptPubKeys; | std::map<COutPoint, CScript> mapprevOutScriptPubKeys; | ||||
std::map<COutPoint, int64_t> mapprevOutValues; | std::map<COutPoint, Amount> mapprevOutValues; | ||||
UniValue inputs = test[0].get_array(); | UniValue inputs = test[0].get_array(); | ||||
bool fValid = true; | bool fValid = true; | ||||
for (size_t inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { | for (size_t inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { | ||||
const UniValue &input = inputs[inpIdx]; | const UniValue &input = inputs[inpIdx]; | ||||
if (!input.isArray()) { | if (!input.isArray()) { | ||||
fValid = false; | fValid = false; | ||||
break; | break; | ||||
} | } | ||||
UniValue vinput = input.get_array(); | UniValue vinput = input.get_array(); | ||||
if (vinput.size() < 3 || vinput.size() > 4) { | if (vinput.size() < 3 || vinput.size() > 4) { | ||||
fValid = false; | fValid = false; | ||||
break; | break; | ||||
} | } | ||||
COutPoint outpoint(uint256S(vinput[0].get_str()), | COutPoint outpoint(uint256S(vinput[0].get_str()), | ||||
vinput[1].get_int()); | vinput[1].get_int()); | ||||
mapprevOutScriptPubKeys[outpoint] = | mapprevOutScriptPubKeys[outpoint] = | ||||
ParseScript(vinput[2].get_str()); | ParseScript(vinput[2].get_str()); | ||||
if (vinput.size() >= 4) { | if (vinput.size() >= 4) { | ||||
mapprevOutValues[outpoint] = vinput[3].get_int64(); | mapprevOutValues[outpoint] = Amount(vinput[3].get_int64()); | ||||
} | } | ||||
} | } | ||||
if (!fValid) { | if (!fValid) { | ||||
BOOST_ERROR("Bad test: " << strTest); | BOOST_ERROR("Bad test: " << strTest); | ||||
continue; | continue; | ||||
} | } | ||||
std::string transaction = test[1].get_str(); | std::string transaction = test[1].get_str(); | ||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, | CDataStream stream(ParseHex(transaction), SER_NETWORK, | ||||
PROTOCOL_VERSION); | PROTOCOL_VERSION); | ||||
CTransaction tx(deserialize, stream); | CTransaction tx(deserialize, stream); | ||||
CValidationState state; | CValidationState state; | ||||
fValid = CheckRegularTransaction(tx, state) && state.IsValid(); | fValid = CheckRegularTransaction(tx, state) && state.IsValid(); | ||||
PrecomputedTransactionData txdata(tx); | PrecomputedTransactionData txdata(tx); | ||||
for (size_t i = 0; i < tx.vin.size() && fValid; i++) { | for (size_t i = 0; i < tx.vin.size() && fValid; i++) { | ||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) { | if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) { | ||||
BOOST_ERROR("Bad test: " << strTest); | BOOST_ERROR("Bad test: " << strTest); | ||||
break; | break; | ||||
} | } | ||||
Amount amount(0); | Amount amount(0); | ||||
if (mapprevOutValues.count(tx.vin[i].prevout)) { | if (0 != mapprevOutValues.count(tx.vin[i].prevout)) { | ||||
amount = mapprevOutValues[tx.vin[i].prevout]; | amount = mapprevOutValues[tx.vin[i].prevout]; | ||||
} | } | ||||
uint32_t verify_flags = ParseScriptFlags(test[2].get_str()); | uint32_t verify_flags = ParseScriptFlags(test[2].get_str()); | ||||
fValid = VerifyScript( | fValid = VerifyScript( | ||||
tx.vin[i].scriptSig, | tx.vin[i].scriptSig, | ||||
mapprevOutScriptPubKeys[tx.vin[i].prevout], verify_flags, | mapprevOutScriptPubKeys[tx.vin[i].prevout], verify_flags, | ||||
TransactionSignatureChecker(&tx, i, amount, txdata), &err); | TransactionSignatureChecker(&tx, i, amount, txdata), &err); | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | SetupDummyInputs(CBasicKeyStore &keystoreRet, CCoinsViewCache &coinsRet) { | ||||
CKey key[4]; | CKey key[4]; | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
key[i].MakeNewKey(i % 2); | key[i].MakeNewKey(i % 2); | ||||
keystoreRet.AddKey(key[i]); | keystoreRet.AddKey(key[i]); | ||||
} | } | ||||
// 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.GetSatoshis(); | dummyTransactions[0].vout[0].nValue = 11 * CENT; | ||||
dummyTransactions[0].vout[0].scriptPubKey | dummyTransactions[0].vout[0].scriptPubKey | ||||
<< ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; | << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; | ||||
dummyTransactions[0].vout[1].nValue = 50 * CENT.GetSatoshis(); | dummyTransactions[0].vout[1].nValue = 50 * CENT; | ||||
dummyTransactions[0].vout[1].scriptPubKey | dummyTransactions[0].vout[1].scriptPubKey | ||||
<< ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; | << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; | ||||
AddCoins(coinsRet, dummyTransactions[0], 0); | AddCoins(coinsRet, dummyTransactions[0], 0); | ||||
dummyTransactions[1].vout.resize(2); | dummyTransactions[1].vout.resize(2); | ||||
dummyTransactions[1].vout[0].nValue = 21 * CENT.GetSatoshis(); | dummyTransactions[1].vout[0].nValue = 21 * CENT; | ||||
dummyTransactions[1].vout[0].scriptPubKey = | dummyTransactions[1].vout[0].scriptPubKey = | ||||
GetScriptForDestination(key[2].GetPubKey().GetID()); | GetScriptForDestination(key[2].GetPubKey().GetID()); | ||||
dummyTransactions[1].vout[1].nValue = 22 * CENT.GetSatoshis(); | dummyTransactions[1].vout[1].nValue = 22 * CENT; | ||||
dummyTransactions[1].vout[1].scriptPubKey = | dummyTransactions[1].vout[1].scriptPubKey = | ||||
GetScriptForDestination(key[3].GetPubKey().GetID()); | GetScriptForDestination(key[3].GetPubKey().GetID()); | ||||
AddCoins(coinsRet, dummyTransactions[1], 0); | AddCoins(coinsRet, dummyTransactions[1], 0); | ||||
return dummyTransactions; | return dummyTransactions; | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(test_Get) { | BOOST_AUTO_TEST_CASE(test_Get) { | ||||
Show All 12 Lines | BOOST_AUTO_TEST_CASE(test_Get) { | ||||
t1.vin[1].prevout.n = 0; | t1.vin[1].prevout.n = 0; | ||||
t1.vin[1].scriptSig << std::vector<uint8_t>(65, 0) | t1.vin[1].scriptSig << std::vector<uint8_t>(65, 0) | ||||
<< std::vector<uint8_t>(33, 4); | << std::vector<uint8_t>(33, 4); | ||||
t1.vin[2].prevout.hash = dummyTransactions[1].GetId(); | t1.vin[2].prevout.hash = dummyTransactions[1].GetId(); | ||||
t1.vin[2].prevout.n = 1; | t1.vin[2].prevout.n = 1; | ||||
t1.vin[2].scriptSig << std::vector<uint8_t>(65, 0) | t1.vin[2].scriptSig << std::vector<uint8_t>(65, 0) | ||||
<< std::vector<uint8_t>(33, 4); | << std::vector<uint8_t>(33, 4); | ||||
t1.vout.resize(2); | t1.vout.resize(2); | ||||
t1.vout[0].nValue = 90 * CENT.GetSatoshis(); | t1.vout[0].nValue = 90 * CENT; | ||||
t1.vout[0].scriptPubKey << OP_1; | t1.vout[0].scriptPubKey << OP_1; | ||||
BOOST_CHECK(AreInputsStandard(t1, coins)); | BOOST_CHECK(AreInputsStandard(t1, coins)); | ||||
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), | BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50 + 21 + 22) * CENT); | ||||
(50 + 21 + 22) * CENT.GetSatoshis()); | |||||
} | } | ||||
void CreateCreditAndSpend(const CKeyStore &keystore, const CScript &outscript, | void CreateCreditAndSpend(const CKeyStore &keystore, const CScript &outscript, | ||||
CTransactionRef &output, CMutableTransaction &input, | CTransactionRef &output, CMutableTransaction &input, | ||||
bool success = true) { | bool success = true) { | ||||
CMutableTransaction outputm; | CMutableTransaction outputm; | ||||
outputm.nVersion = 1; | outputm.nVersion = 1; | ||||
outputm.vin.resize(1); | outputm.vin.resize(1); | ||||
outputm.vin[0].prevout.SetNull(); | outputm.vin[0].prevout.SetNull(); | ||||
outputm.vin[0].scriptSig = CScript(); | outputm.vin[0].scriptSig = CScript(); | ||||
outputm.vout.resize(1); | outputm.vout.resize(1); | ||||
outputm.vout[0].nValue = 1; | outputm.vout[0].nValue = Amount(1); | ||||
outputm.vout[0].scriptPubKey = outscript; | outputm.vout[0].scriptPubKey = outscript; | ||||
CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssout << outputm; | ssout << outputm; | ||||
ssout >> output; | ssout >> output; | ||||
BOOST_CHECK_EQUAL(output->vin.size(), 1); | BOOST_CHECK_EQUAL(output->vin.size(), 1UL); | ||||
BOOST_CHECK(output->vin[0] == outputm.vin[0]); | BOOST_CHECK(output->vin[0] == outputm.vin[0]); | ||||
BOOST_CHECK_EQUAL(output->vout.size(), 1); | BOOST_CHECK_EQUAL(output->vout.size(), 1UL); | ||||
BOOST_CHECK(output->vout[0] == outputm.vout[0]); | BOOST_CHECK(output->vout[0] == outputm.vout[0]); | ||||
CMutableTransaction inputm; | CMutableTransaction inputm; | ||||
inputm.nVersion = 1; | inputm.nVersion = 1; | ||||
inputm.vin.resize(1); | inputm.vin.resize(1); | ||||
inputm.vin[0].prevout.hash = output->GetId(); | inputm.vin[0].prevout.hash = output->GetId(); | ||||
inputm.vin[0].prevout.n = 0; | inputm.vin[0].prevout.n = 0; | ||||
inputm.vout.resize(1); | inputm.vout.resize(1); | ||||
inputm.vout[0].nValue = 1; | inputm.vout[0].nValue = Amount(1); | ||||
inputm.vout[0].scriptPubKey = CScript(); | inputm.vout[0].scriptPubKey = CScript(); | ||||
bool ret = SignSignature(keystore, *output, inputm, 0, | bool ret = SignSignature(keystore, *output, inputm, 0, | ||||
SIGHASH_ALL | SIGHASH_FORKID); | SIGHASH_ALL | SIGHASH_FORKID); | ||||
BOOST_CHECK_EQUAL(ret, success); | BOOST_CHECK_EQUAL(ret, success); | ||||
CDataStream ssin(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssin(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssin << inputm; | ssin << inputm; | ||||
ssin >> input; | ssin >> input; | ||||
BOOST_CHECK_EQUAL(input.vin.size(), 1); | BOOST_CHECK_EQUAL(input.vin.size(), 1UL); | ||||
BOOST_CHECK(input.vin[0] == inputm.vin[0]); | BOOST_CHECK(input.vin[0] == inputm.vin[0]); | ||||
BOOST_CHECK_EQUAL(input.vout.size(), 1); | BOOST_CHECK_EQUAL(input.vout.size(), 1UL); | ||||
BOOST_CHECK(input.vout[0] == inputm.vout[0]); | BOOST_CHECK(input.vout[0] == inputm.vout[0]); | ||||
} | } | ||||
void CheckWithFlag(const CTransactionRef &output, | void CheckWithFlag(const CTransactionRef &output, | ||||
const CMutableTransaction &input, int flags, bool success) { | const CMutableTransaction &input, int flags, bool success) { | ||||
ScriptError error; | ScriptError error; | ||||
CTransaction inputi(input); | CTransaction inputi(input); | ||||
bool ret = VerifyScript( | bool ret = VerifyScript( | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | std::vector<CMutableTransaction> dummyTransactions = | ||||
SetupDummyInputs(keystore, coins); | SetupDummyInputs(keystore, coins); | ||||
CMutableTransaction t; | CMutableTransaction t; | ||||
t.vin.resize(1); | t.vin.resize(1); | ||||
t.vin[0].prevout.hash = dummyTransactions[0].GetId(); | t.vin[0].prevout.hash = dummyTransactions[0].GetId(); | ||||
t.vin[0].prevout.n = 1; | t.vin[0].prevout.n = 1; | ||||
t.vin[0].scriptSig << std::vector<uint8_t>(65, 0); | t.vin[0].scriptSig << std::vector<uint8_t>(65, 0); | ||||
t.vout.resize(1); | t.vout.resize(1); | ||||
t.vout[0].nValue = 90 * CENT.GetSatoshis(); | t.vout[0].nValue = 90 * CENT; | ||||
CKey key; | CKey key; | ||||
key.MakeNewKey(true); | key.MakeNewKey(true); | ||||
t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); | t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); | ||||
std::string reason; | std::string reason; | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(t, reason)); | ||||
// Check dust with default relay fee: | // Check dust with default relay fee: | ||||
Amount nDustThreshold = 3 * 182 * dustRelayFee.GetFeePerK() / 1000; | Amount nDustThreshold = 3 * 182 * dustRelayFee.GetFeePerK() / 1000; | ||||
BOOST_CHECK_EQUAL(nDustThreshold, Amount(546)); | BOOST_CHECK_EQUAL(nDustThreshold, Amount(546)); | ||||
// dust: | // dust: | ||||
t.vout[0].nValue = nDustThreshold - 1; | t.vout[0].nValue = nDustThreshold - Amount(1); | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(t, reason)); | ||||
// not dust: | // not dust: | ||||
t.vout[0].nValue = nDustThreshold; | t.vout[0].nValue = nDustThreshold; | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(t, reason)); | ||||
// Check dust with odd relay fee to verify rounding: | // Check dust with odd relay fee to verify rounding: | ||||
// nDustThreshold = 182 * 1234 / 1000 * 3 | // nDustThreshold = 182 * 1234 / 1000 * 3 | ||||
dustRelayFee = CFeeRate(1234); | dustRelayFee = CFeeRate(Amount(1234)); | ||||
// dust: | // dust: | ||||
t.vout[0].nValue = 672 - 1; | t.vout[0].nValue = Amount(672 - 1); | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(t, reason)); | ||||
// not dust: | // not dust: | ||||
t.vout[0].nValue = 672; | t.vout[0].nValue = Amount(672); | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(t, reason)); | ||||
dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE); | dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE); | ||||
t.vout[0].scriptPubKey = CScript() << OP_1; | t.vout[0].scriptPubKey = CScript() << OP_1; | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(t, reason)); | ||||
// MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard) | // MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard) | ||||
t.vout[0].scriptPubKey = | t.vout[0].scriptPubKey = | ||||
▲ Show 20 Lines • Show All 70 Lines • Show Last 20 Lines |