Changeset View
Changeset View
Standalone View
Standalone View
src/test/transaction_tests.cpp
Show First 20 Lines • Show All 235 Lines • ▼ Show 20 Lines | uint8_t ch[] = { | ||||
0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, | 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, | ||||
0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, | 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, | ||||
0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; | 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||||
std::vector<uint8_t> vch(ch, ch + sizeof(ch) - 1); | std::vector<uint8_t> vch(ch, ch + sizeof(ch) - 1); | ||||
CDataStream stream(vch, SER_DISK, CLIENT_VERSION); | CDataStream stream(vch, SER_DISK, CLIENT_VERSION); | ||||
CMutableTransaction tx; | CMutableTransaction tx; | ||||
stream >> tx; | stream >> tx; | ||||
CValidationState state; | CValidationState state; | ||||
BOOST_CHECK_MESSAGE(CheckRegularTransaction(tx, state) && state.IsValid(), | BOOST_CHECK_MESSAGE(CheckRegularTransaction(CTransaction(tx), state) && | ||||
state.IsValid(), | |||||
"Simple deserialized transaction should be valid."); | "Simple deserialized transaction should be valid."); | ||||
// Check that duplicate txins fail | // Check that duplicate txins fail | ||||
tx.vin.push_back(tx.vin[0]); | tx.vin.push_back(tx.vin[0]); | ||||
BOOST_CHECK_MESSAGE(!CheckRegularTransaction(tx, state) || !state.IsValid(), | BOOST_CHECK_MESSAGE(!CheckRegularTransaction(CTransaction(tx), state) || | ||||
!state.IsValid(), | |||||
"Transaction with duplicate txins should be invalid."); | "Transaction with duplicate txins should be invalid."); | ||||
} | } | ||||
// | // | ||||
// 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 | ||||
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs | // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs | ||||
// paid to a TX_PUBKEYHASH. | // paid to a TX_PUBKEYHASH. | ||||
Show All 13 Lines | SetupDummyInputs(CBasicKeyStore &keystoreRet, CCoinsViewCache &coinsRet) { | ||||
// 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 | dummyTransactions[0].vout[0].scriptPubKey | ||||
<< ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; | << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; | ||||
dummyTransactions[0].vout[1].nValue = 50 * CENT; | 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, CTransaction(dummyTransactions[0]), 0); | ||||
dummyTransactions[1].vout.resize(2); | dummyTransactions[1].vout.resize(2); | ||||
dummyTransactions[1].vout[0].nValue = 21 * CENT; | 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; | 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, CTransaction(dummyTransactions[1]), 0); | ||||
return dummyTransactions; | return dummyTransactions; | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(test_Get) { | BOOST_AUTO_TEST_CASE(test_Get) { | ||||
CBasicKeyStore keystore; | CBasicKeyStore keystore; | ||||
CCoinsView coinsDummy; | CCoinsView coinsDummy; | ||||
CCoinsViewCache coins(&coinsDummy); | CCoinsViewCache coins(&coinsDummy); | ||||
Show All 12 Lines | BOOST_AUTO_TEST_CASE(test_Get) { | ||||
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; | 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(CTransaction(t1), coins)); | ||||
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50 + 21 + 22) * CENT); | BOOST_CHECK_EQUAL(coins.GetValueIn(CTransaction(t1)), | ||||
(50 + 21 + 22) * CENT); | |||||
} | } | ||||
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); | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(test_IsStandard) { | ||||
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; | 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(CTransaction(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 - Amount(1); | t.vout[0].nValue = nDustThreshold - Amount(1); | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
// not dust: | // not dust: | ||||
t.vout[0].nValue = nDustThreshold; | t.vout[0].nValue = nDustThreshold; | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(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(Amount(1234)); | dustRelayFee = CFeeRate(Amount(1234)); | ||||
// dust: | // dust: | ||||
t.vout[0].nValue = Amount(672 - 1); | t.vout[0].nValue = Amount(672 - 1); | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
// not dust: | // not dust: | ||||
t.vout[0].nValue = Amount(672); | t.vout[0].nValue = Amount(672); | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(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(CTransaction(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 = | ||||
CScript() << OP_RETURN | CScript() << OP_RETURN | ||||
<< ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | ||||
"a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548" | "a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548" | ||||
"271967f1a67130b7105cd6a828e03909a67962e0ea1f61de" | "271967f1a67130b7105cd6a828e03909a67962e0ea1f61de" | ||||
"b649f6bc3f4cef38"); | "b649f6bc3f4cef38"); | ||||
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); | BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size()); | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); | ||||
// MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard) | // MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard) | ||||
t.vout[0].scriptPubKey = | t.vout[0].scriptPubKey = | ||||
CScript() << OP_RETURN | CScript() << OP_RETURN | ||||
<< ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | ||||
"a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548" | "a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548" | ||||
"271967f1a67130b7105cd6a828e03909a67962e0ea1f61de" | "271967f1a67130b7105cd6a828e03909a67962e0ea1f61de" | ||||
"b649f6bc3f4cef3800"); | "b649f6bc3f4cef3800"); | ||||
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); | BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size()); | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
// Data payload can be encoded in any way... | // Data payload can be encoded in any way... | ||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex(""); | t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex(""); | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); | ||||
t.vout[0].scriptPubKey = CScript() | t.vout[0].scriptPubKey = CScript() | ||||
<< OP_RETURN << ParseHex("00") << ParseHex("01"); | << OP_RETURN << ParseHex("00") << ParseHex("01"); | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); | ||||
// OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()! | // OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()! | ||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 | t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 | ||||
<< ParseHex("01") << 2 << 3 << 4 << 5 | << ParseHex("01") << 2 << 3 << 4 << 5 | ||||
<< 6 << 7 << 8 << 9 << 10 << 11 << 12 | << 6 << 7 << 8 << 9 << 10 << 11 << 12 | ||||
<< 13 << 14 << 15 << 16; | << 13 << 14 << 15 << 16; | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); | ||||
t.vout[0].scriptPubKey = CScript() | t.vout[0].scriptPubKey = CScript() | ||||
<< OP_RETURN << 0 << ParseHex("01") << 2 | << OP_RETURN << 0 << ParseHex("01") << 2 | ||||
<< ParseHex("fffffffffffffffffffffffffffffffffffff" | << ParseHex("fffffffffffffffffffffffffffffffffffff" | ||||
"fffffffffffffffffffffffffffffffffff"); | "fffffffffffffffffffffffffffffffffff"); | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); | ||||
// ...so long as it only contains PUSHDATA's | // ...so long as it only contains PUSHDATA's | ||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN; | t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN; | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
// TX_NULL_DATA w/o PUSHDATA | // TX_NULL_DATA w/o PUSHDATA | ||||
t.vout.resize(1); | t.vout.resize(1); | ||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN; | t.vout[0].scriptPubKey = CScript() << OP_RETURN; | ||||
BOOST_CHECK(IsStandardTx(t, reason)); | BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); | ||||
// Only one TX_NULL_DATA permitted in all cases | // Only one TX_NULL_DATA permitted in all cases | ||||
t.vout.resize(2); | t.vout.resize(2); | ||||
t.vout[0].scriptPubKey = | t.vout[0].scriptPubKey = | ||||
CScript() << OP_RETURN | CScript() << OP_RETURN | ||||
<< ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | ||||
"a67962e0ea1f61deb649f6bc3f4cef38"); | "a67962e0ea1f61deb649f6bc3f4cef38"); | ||||
t.vout[1].scriptPubKey = | t.vout[1].scriptPubKey = | ||||
CScript() << OP_RETURN | CScript() << OP_RETURN | ||||
<< ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | ||||
"a67962e0ea1f61deb649f6bc3f4cef38"); | "a67962e0ea1f61deb649f6bc3f4cef38"); | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
t.vout[0].scriptPubKey = | t.vout[0].scriptPubKey = | ||||
CScript() << OP_RETURN | CScript() << OP_RETURN | ||||
<< ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | ||||
"a67962e0ea1f61deb649f6bc3f4cef38"); | "a67962e0ea1f61deb649f6bc3f4cef38"); | ||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN; | t.vout[1].scriptPubKey = CScript() << OP_RETURN; | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN; | t.vout[0].scriptPubKey = CScript() << OP_RETURN; | ||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN; | t.vout[1].scriptPubKey = CScript() << OP_RETURN; | ||||
BOOST_CHECK(!IsStandardTx(t, reason)); | BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |