diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/data/tx_invalid.json | 54 | ||||
-rw-r--r-- | src/test/data/tx_valid.json | 84 | ||||
-rw-r--r-- | src/test/miner_tests.cpp | 159 | ||||
-rw-r--r-- | src/test/script_tests.cpp | 4 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 2 | ||||
-rw-r--r-- | src/test/test_bitcoin.h | 4 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 3 | ||||
-rw-r--r-- | src/test/versionbits_tests.cpp | 316 |
8 files changed, 587 insertions, 39 deletions
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index 9025841949..2d7d9b9585 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -201,5 +201,59 @@ [[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], "010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"], +["CHECKSEQUENCEVERIFY tests"], + +["By-height locks, with argument just beyond txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument missing"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument negative with by-blockheight txin.nSequence=0"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument/tx height/time mismatch, both versions"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], +"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Failure due to insufficient tx.nVersion (<2)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 76d29bcf26..717ad19549 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -233,5 +233,89 @@ [[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], "010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"], +["CHECKSEQUENCEVERIFY tests"], + +["By-height locks, with argument == 0 and == txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["By-time locks, with argument == 0 and == txin.nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Upper sequence with upper sequence is fine"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 2^31 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 2^32-1 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Argument 3<<31 with various nSequence"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["5 byte non-minimally-encoded operandss are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["The argument can be calculated rather than created directly by a PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD NOP3 1"]], +"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Valid CHECKSEQUENCEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + +["Valid CHECKSEQUENCEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], +"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"], + ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 71b52409b3..ab6485081c 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -57,6 +57,20 @@ struct { {2, 0xbbbeb305}, {2, 0xfe1c810a}, }; +CBlockIndex CreateBlockIndex(int nHeight) +{ + CBlockIndex index; + index.nHeight = nHeight; + index.pprev = chainActive.Tip(); + return index; +} + +bool TestSequenceLocks(const CTransaction &tx, int flags) +{ + LOCK(mempool.cs); + return CheckSequenceLocks(tx, flags); +} + // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { @@ -79,6 +93,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // We can't make transactions until we have inputs // Therefore, load 100 blocks :) + int baseheight = 0; std::vector<CTransaction*>txFirst; for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) { @@ -92,7 +107,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txCoinbase.vin[0].scriptSig.push_back(chainActive.Height()); txCoinbase.vout[0].scriptPubKey = CScript(); pblock->vtx[0] = CTransaction(txCoinbase); - if (txFirst.size() < 2) + if (txFirst.size() == 0) + baseheight = chainActive.Height(); + if (txFirst.size() < 4) txFirst.push_back(new CTransaction(pblock->vtx[0])); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; @@ -230,59 +247,133 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // subsidy changing int nHeight = chainActive.Height(); - chainActive.Tip()->nHeight = 209999; + // Create an actual 209999-long block chain (without valid blocks). + while (chainActive.Tip()->nHeight < 209999) { + CBlockIndex* prev = chainActive.Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(GetRandHash()); + pcoinsTip->SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + chainActive.SetTip(next); + } BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; - chainActive.Tip()->nHeight = 210000; + // Extend to a 210000-long block chain. + while (chainActive.Tip()->nHeight < 210000) { + CBlockIndex* prev = chainActive.Tip(); + CBlockIndex* next = new CBlockIndex(); + next->phashBlock = new uint256(GetRandHash()); + pcoinsTip->SetBestBlock(next->GetBlockHash()); + next->pprev = prev; + next->nHeight = prev->nHeight + 1; + next->BuildSkip(); + chainActive.SetTip(next); + } BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; - chainActive.Tip()->nHeight = nHeight; + // Delete the dummy blocks again. + while (chainActive.Tip()->nHeight > nHeight) { + CBlockIndex* del = chainActive.Tip(); + chainActive.SetTip(del->pprev); + pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); + delete del->phashBlock; + delete del; + } // non-final txs in mempool SetMockTime(chainActive.Tip()->GetMedianTimePast()+1); + int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST; + // height map + std::vector<int> prevheights; - // height locked - tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + // relative height locked + tx.nVersion = 2; + tx.vin.resize(1); + prevheights.resize(1); + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction + tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; - tx.vin[0].nSequence = 0; + tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block + prevheights[0] = baseheight + 1; + tx.vout.resize(1); tx.vout[0].nValue = 4900000000LL; tx.vout[0].scriptPubKey = CScript() << OP_1; - tx.nLockTime = chainActive.Tip()->nHeight+1; + tx.nLockTime = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST)); - - // time locked - tx2.vin.resize(1); - tx2.vin[0].prevout.hash = txFirst[1]->GetHash(); - tx2.vin[0].prevout.n = 0; - tx2.vin[0].scriptSig = CScript() << OP_1; - tx2.vin[0].nSequence = 0; - tx2.vout.resize(1); - tx2.vout[0].nValue = 4900000000LL; - tx2.vout[0].scriptPubKey = CScript() << OP_1; - tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1; - hash = tx2.GetHash(); - mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx2)); - BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST)); + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block + + // relative time locked + tx.vin[0].prevout.hash = txFirst[1]->GetHash(); + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block + prevheights[0] = baseheight + 2; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast + BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP + + // absolute height locked + tx.vin[0].prevout.hash = txFirst[2]->GetHash(); + tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; + prevheights[0] = baseheight + 3; + tx.nLockTime = chainActive.Tip()->nHeight + 1; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block + + // absolute time locked + tx.vin[0].prevout.hash = txFirst[3]->GetHash(); + tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); + prevheights.resize(1); + prevheights[0] = baseheight + 4; + hash = tx.GetHash(); + mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later + + // mempool-dependent transactions (not added) + tx.vin[0].prevout.hash = hash; + prevheights[0] = chainActive.Tip()->nHeight + 1; + tx.nLockTime = 0; + tx.vin[0].nSequence = 0; + BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + tx.vin[0].nSequence = 1; + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; + BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; + BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); - // Neither tx should have make it into the template. - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); + // None of the of the absolute height/time locked tx should have made + // it into the template because we still check IsFinalTx in CreateNewBlock, + // but relative locked txs will if inconsistently added to mempool. + // For now these will still generate a valid template until BIP68 soft fork + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); delete pblocktemplate; - - // However if we advance height and time by one, both will. + // However if we advance height by 1 and time by 512, all of them should be mined + for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) + chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast chainActive.Tip()->nHeight++; - SetMockTime(chainActive.Tip()->GetMedianTimePast()+2); - - // FIXME: we should *actually* create a new block so the following test - // works; CheckFinalTx() isn't fooled by monkey-patching nHeight. - //BOOST_CHECK(CheckFinalTx(tx)); - //BOOST_CHECK(CheckFinalTx(tx2)); + SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2); + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5); delete pblocktemplate; chainActive.Tip()->nHeight--; diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 10175ebe8e..f370a4aa2a 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -63,7 +63,7 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) txCredit.vout.resize(1); txCredit.vin[0].prevout.SetNull(); txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); - txCredit.vin[0].nSequence = std::numeric_limits<unsigned int>::max(); + txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txCredit.vout[0].scriptPubKey = scriptPubKey; txCredit.vout[0].nValue = 0; @@ -80,7 +80,7 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu txSpend.vin[0].prevout.hash = txCredit.GetHash(); txSpend.vin[0].prevout.n = 0; txSpend.vin[0].scriptSig = scriptSig; - txSpend.vin[0].nSequence = std::numeric_limits<unsigned int>::max(); + txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = 0; diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index f81050b15d..f278d7e399 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -150,7 +150,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPo CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight, - hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount); + hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); } void Shutdown(void* parg) diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 273bfdd7f4..37bcb9b57c 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -5,6 +5,7 @@ #include "key.h" #include "pubkey.h" #include "txdb.h" +#include "txmempool.h" #include <boost/filesystem.hpp> #include <boost/thread.hpp> @@ -67,7 +68,8 @@ struct TestMemPoolEntryHelper bool hadNoDependencies; bool spendsCoinbase; unsigned int sigOpCount; - + LockPoints lp; + TestMemPoolEntryHelper() : nFee(0), nTime(0), dPriority(0.0), nHeight(1), hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1) { } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index c27f194b55..d9195bf345 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -44,7 +44,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK) - (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY); + (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) + (string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY); unsigned int ParseScriptFlags(string strFlags) { diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp new file mode 100644 index 0000000000..1f86a06a3f --- /dev/null +++ b/src/test/versionbits_tests.cpp @@ -0,0 +1,316 @@ +// Copyright (c) 2014-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chain.h" +#include "random.h" +#include "versionbits.h" +#include "test/test_bitcoin.h" +#include "chainparams.h" +#include "main.h" +#include "consensus/params.h" + +#include <boost/test/unit_test.hpp> + +/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */ +int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; } + +static const Consensus::Params paramsDummy = Consensus::Params(); + +class TestConditionChecker : public AbstractThresholdConditionChecker +{ +private: + mutable ThresholdConditionCache cache; + +public: + int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); } + int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); } + int Period(const Consensus::Params& params) const { return 1000; } + int Threshold(const Consensus::Params& params) const { return 900; } + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); } + + ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); } +}; + +#define CHECKERS 6 + +class VersionBitsTester +{ + // A fake blockchain + std::vector<CBlockIndex*> vpblock; + + // 6 independent checkers for the same bit. + // The first one performs all checks, the second only 50%, the third only 25%, etc... + // This is to test whether lack of cached information leads to the same results. + TestConditionChecker checker[CHECKERS]; + + // Test counter (to identify failures) + int num; + +public: + VersionBitsTester() : num(0) {} + + VersionBitsTester& Reset() { + for (unsigned int i = 0; i < vpblock.size(); i++) { + delete vpblock[i]; + } + for (unsigned int i = 0; i < CHECKERS; i++) { + checker[i] = TestConditionChecker(); + } + vpblock.clear(); + return *this; + } + + ~VersionBitsTester() { + Reset(); + } + + VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) { + while (vpblock.size() < height) { + CBlockIndex* pindex = new CBlockIndex(); + pindex->nHeight = vpblock.size(); + pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL; + pindex->nTime = nTime; + pindex->nVersion = nVersion; + pindex->BuildSkip(); + vpblock.push_back(pindex); + } + return *this; + } + + VersionBitsTester& TestDefined() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestStarted() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestLockedIn() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestActive() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num)); + } + } + num++; + return *this; + } + + VersionBitsTester& TestFailed() { + for (int i = 0; i < CHECKERS; i++) { + if ((insecure_rand() & ((1 << i) - 1)) == 0) { + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num)); + } + } + num++; + return *this; + } + + CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; } +}; + +BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(versionbits_test) +{ + for (int i = 0; i < 64; i++) { + // DEFINED -> FAILED + VersionBitsTester().TestDefined() + .Mine(1, TestTime(1), 0x100).TestDefined() + .Mine(11, TestTime(11), 0x100).TestDefined() + .Mine(989, TestTime(989), 0x100).TestDefined() + .Mine(999, TestTime(20000), 0x100).TestDefined() + .Mine(1000, TestTime(20000), 0x100).TestFailed() + .Mine(1999, TestTime(30001), 0x100).TestFailed() + .Mine(2000, TestTime(30002), 0x100).TestFailed() + .Mine(2001, TestTime(30003), 0x100).TestFailed() + .Mine(2999, TestTime(30004), 0x100).TestFailed() + .Mine(3000, TestTime(30005), 0x100).TestFailed() + + // DEFINED -> STARTED -> FAILED + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period + .Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks + .Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks + .Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000) + .Mine(4000, TestTime(20010), 0x100).TestFailed() + + // DEFINED -> STARTED -> FAILED while threshold reached + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period + .Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks + .Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new) + .Mine(3999, TestTime(30001), 0).TestFailed() + .Mine(4000, TestTime(30002), 0).TestFailed() + .Mine(14333, TestTime(30003), 0).TestFailed() + .Mine(24000, TestTime(40000), 0).TestFailed() + + // DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE + .Reset().TestDefined() + .Mine(1, TestTime(1), 0).TestDefined() + .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined + .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period + .Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks + .Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks + .Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks + .Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000) + .Mine(3999, TestTime(30001), 0).TestLockedIn() + .Mine(4000, TestTime(30002), 0).TestActive() + .Mine(14333, TestTime(30003), 0).TestActive() + .Mine(24000, TestTime(40000), 0).TestActive(); + } + + // Sanity checks of version bit deployments + const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus(); + for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { + uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i); + // Make sure that no deployment tries to set an invalid bit. + BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask); + + // Verify that the deployment windows of different deployment using the + // same bit are disjoint. + // This test may need modification at such time as a new deployment + // is proposed that reuses the bit of an activated soft fork, before the + // end time of that soft fork. (Alternatively, the end time of that + // activated soft fork could be later changed to be earlier to avoid + // overlap.) + for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) { + if (VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)j) == bitmask) { + BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout || + mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout); + } + } + } +} + +BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +{ + // Check that ComputeBlockVersion will set the appropriate bit correctly + // on mainnet. + const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus(); + + // Use the TESTDUMMY deployment for testing purposes. + int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit; + int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime; + int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout; + + assert(nStartTime < nTimeout); + + // In the first chain, test that the bit is set by CBV until it has failed. + // In the second chain, test the bit is set by CBV while STARTED and + // LOCKED-IN, and then no longer set while ACTIVE. + VersionBitsTester firstChain, secondChain; + + // Start generating blocks before nStartTime + int64_t nTime = nStartTime - 1; + + // Before MedianTimePast of the chain has crossed nStartTime, the bit + // should not be set. + CBlockIndex *lastBlock = NULL; + lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + + // Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet. + for (int i=1; i<2012; i++) { + lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + // This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens + // to be 4, and the bit we're testing happens to be bit 28. + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + } + // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so + // CBV should still not yet set the bit. + nTime = nStartTime; + for (int i=2012; i<=2016; i++) { + lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + } + + // Advance to the next period and transition to STARTED, + lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + // so ComputeBlockVersion should now set the bit, + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + // and should also be using the VERSIONBITS_TOP_BITS. + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + + // Check that ComputeBlockVersion will set the bit until nTimeout + nTime += 600; + int blocksToMine = 4032; // test blocks for up to 2 time periods + int nHeight = 6048; + // These blocks are all before nTimeout is reached. + while (nTime < nTimeout && blocksToMine > 0) { + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + blocksToMine--; + nTime += 600; + nHeight += 1; + }; + + nTime = nTimeout; + // FAILED is only triggered at the end of a period, so CBV should be setting + // the bit until the period transition. + for (int i=0; i<2015; i++) { + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + nHeight += 1; + } + // The next block should trigger no longer setting the bit. + lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + + // On a new chain: + // verify that the bit will be set after lock-in, and then stop being set + // after activation. + nTime = nStartTime; + + // Mine one period worth of blocks, and check that the bit will be on for the + // next period. + lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + + // Mine another period worth of blocks, signaling the new bit. + lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip(); + // After one period of setting the bit on each block, it should have locked in. + // We keep setting the bit for one more period though, until activation. + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + + // Now check that we keep mining the block until the end of this period, and + // then stop at the beginning of the next period. + lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0); + lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); + BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0); + + // Finally, verify that after a soft fork has activated, CBV no longer uses + // VERSIONBITS_LAST_OLD_BLOCK_VERSION. + //BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); +} + + +BOOST_AUTO_TEST_SUITE_END() |