If/when CTransaction::CURRENT_VERSION is incremented, this will break CChainParams and the miner tests. This fix sets the transaction version explicitly where we depend on the hash value (genesis block, proof of work checks).
273 lines
11 KiB
C++
273 lines
11 KiB
C++
// Copyright (c) 2011-2014 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 "consensus/validation.h"
|
|
#include "main.h"
|
|
#include "miner.h"
|
|
#include "pubkey.h"
|
|
#include "uint256.h"
|
|
#include "util.h"
|
|
|
|
#include "test/test_bitcoin.h"
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
|
|
|
|
static
|
|
struct {
|
|
unsigned char extranonce;
|
|
unsigned int nonce;
|
|
} blockinfo[] = {
|
|
{4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5},
|
|
{2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84},
|
|
{2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4},
|
|
{2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa},
|
|
{1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb},
|
|
{3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406},
|
|
{2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38},
|
|
{2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9},
|
|
{1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7},
|
|
{2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34},
|
|
{1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c},
|
|
{1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f},
|
|
{1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81},
|
|
{1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78},
|
|
{1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c},
|
|
{2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049},
|
|
{2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169},
|
|
{1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10},
|
|
{1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d},
|
|
{2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323},
|
|
{1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6},
|
|
{1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408},
|
|
{1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602},
|
|
{0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459},
|
|
{2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668},
|
|
{1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce},
|
|
{2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e},
|
|
{2, 0xbbbeb305}, {2, 0xfe1c810a},
|
|
};
|
|
|
|
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
|
|
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|
{
|
|
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
|
|
CBlockTemplate *pblocktemplate;
|
|
CMutableTransaction tx,tx2;
|
|
CScript script;
|
|
uint256 hash;
|
|
|
|
LOCK(cs_main);
|
|
fCheckpointsEnabled = false;
|
|
|
|
// Simple block creation, nothing special yet:
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
|
|
// We can't make transactions until we have inputs
|
|
// Therefore, load 100 blocks :)
|
|
std::vector<CTransaction*>txFirst;
|
|
for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
|
|
{
|
|
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
|
pblock->nVersion = 1;
|
|
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
|
|
CMutableTransaction txCoinbase(pblock->vtx[0]);
|
|
txCoinbase.nVersion = 1;
|
|
txCoinbase.vin[0].scriptSig = CScript();
|
|
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
|
|
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
|
|
txCoinbase.vout[0].scriptPubKey = CScript();
|
|
pblock->vtx[0] = CTransaction(txCoinbase);
|
|
if (txFirst.size() < 2)
|
|
txFirst.push_back(new CTransaction(pblock->vtx[0]));
|
|
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
|
pblock->nNonce = blockinfo[i].nonce;
|
|
CValidationState state;
|
|
BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));
|
|
BOOST_CHECK(state.IsValid());
|
|
pblock->hashPrevBlock = pblock->GetHash();
|
|
}
|
|
delete pblocktemplate;
|
|
|
|
// Just to make sure we can still make simple blocks
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
|
|
// block sigops > limit: 1000 CHECKMULTISIG + 1
|
|
tx.vin.resize(1);
|
|
// NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
|
|
tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;
|
|
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
|
tx.vin[0].prevout.n = 0;
|
|
tx.vout.resize(1);
|
|
tx.vout[0].nValue = 5000000000LL;
|
|
for (unsigned int i = 0; i < 1001; ++i)
|
|
{
|
|
tx.vout[0].nValue -= 1000000;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
tx.vin[0].prevout.hash = hash;
|
|
}
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// block size > limit
|
|
tx.vin[0].scriptSig = CScript();
|
|
// 18 * (520char + DROP) + OP_1 = 9433 bytes
|
|
std::vector<unsigned char> vchData(520);
|
|
for (unsigned int i = 0; i < 18; ++i)
|
|
tx.vin[0].scriptSig << vchData << OP_DROP;
|
|
tx.vin[0].scriptSig << OP_1;
|
|
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
|
tx.vout[0].nValue = 5000000000LL;
|
|
for (unsigned int i = 0; i < 128; ++i)
|
|
{
|
|
tx.vout[0].nValue -= 10000000;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
tx.vin[0].prevout.hash = hash;
|
|
}
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// orphan in mempool
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// child with higher priority than parent
|
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
|
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
|
tx.vout[0].nValue = 4900000000LL;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
tx.vin[0].prevout.hash = hash;
|
|
tx.vin.resize(2);
|
|
tx.vin[1].scriptSig = CScript() << OP_1;
|
|
tx.vin[1].prevout.hash = txFirst[0]->GetHash();
|
|
tx.vin[1].prevout.n = 0;
|
|
tx.vout[0].nValue = 5900000000LL;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// coinbase in mempool
|
|
tx.vin.resize(1);
|
|
tx.vin[0].prevout.SetNull();
|
|
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
|
|
tx.vout[0].nValue = 0;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// invalid (pre-p2sh) txn in mempool
|
|
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
|
tx.vin[0].prevout.n = 0;
|
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
|
tx.vout[0].nValue = 4900000000LL;
|
|
script = CScript() << OP_0;
|
|
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
tx.vin[0].prevout.hash = hash;
|
|
tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
|
|
tx.vout[0].nValue -= 1000000;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// double spend txn pair in mempool
|
|
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
|
tx.vout[0].nValue = 4900000000LL;
|
|
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
tx.vout[0].scriptPubKey = CScript() << OP_2;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
mempool.clear();
|
|
|
|
// subsidy changing
|
|
int nHeight = chainActive.Height();
|
|
chainActive.Tip()->nHeight = 209999;
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
chainActive.Tip()->nHeight = 210000;
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
delete pblocktemplate;
|
|
chainActive.Tip()->nHeight = nHeight;
|
|
|
|
// non-final txs in mempool
|
|
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
|
|
|
// height locked
|
|
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
|
tx.vin[0].nSequence = 0;
|
|
tx.vout[0].nValue = 4900000000LL;
|
|
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
|
tx.nLockTime = chainActive.Tip()->nHeight+1;
|
|
hash = tx.GetHash();
|
|
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(!CheckFinalTx(tx));
|
|
|
|
// 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, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11));
|
|
BOOST_CHECK(!CheckFinalTx(tx2));
|
|
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
|
|
// Neither tx should have make it into the template.
|
|
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1);
|
|
delete pblocktemplate;
|
|
|
|
// However if we advance height and time by one, both will.
|
|
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));
|
|
|
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
|
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
|
|
delete pblocktemplate;
|
|
|
|
chainActive.Tip()->nHeight--;
|
|
SetMockTime(0);
|
|
mempool.clear();
|
|
|
|
BOOST_FOREACH(CTransaction *tx, txFirst)
|
|
delete tx;
|
|
|
|
fCheckpointsEnabled = true;
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|