1 #include <gtest/gtest.h>
2 #include <gmock/gmock.h>
4 #include "consensus/validation.h"
7 #include "zcash/Proof.hpp"
9 class MockCValidationState : public CValidationState {
11 MOCK_METHOD5(DoS, bool(int level, bool ret,
12 unsigned char chRejectCodeIn, std::string strRejectReasonIn,
14 MOCK_METHOD3(Invalid, bool(bool ret,
15 unsigned char _chRejectCode, std::string _strRejectReason));
16 MOCK_METHOD1(Error, bool(std::string strRejectReasonIn));
17 MOCK_CONST_METHOD0(IsValid, bool());
18 MOCK_CONST_METHOD0(IsInvalid, bool());
19 MOCK_CONST_METHOD0(IsError, bool());
20 MOCK_CONST_METHOD1(IsInvalid, bool(int &nDoSOut));
21 MOCK_CONST_METHOD0(CorruptionPossible, bool());
22 MOCK_CONST_METHOD0(GetRejectCode, unsigned char());
23 MOCK_CONST_METHOD0(GetRejectReason, std::string());
27 TEST(CheckBlock, VersionTooLow) {
28 auto verifier = libzcash::ProofVerifier::Strict();
33 MockCValidationState state;
34 EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1);
35 EXPECT_FALSE(CheckBlock(&futureblock, 0, 0, block, state, Params(), verifier, false, false));
39 // Test that a Sprout tx with negative version is still rejected
40 // by CheckBlock under Sprout consensus rules.
41 TEST(CheckBlock, BlockSproutRejectsBadVersion) {
42 SelectParams(CBaseChainParams::MAIN);
44 CMutableTransaction mtx;
46 mtx.vin[0].prevout.SetNull();
47 mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
49 mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
50 mtx.vout[0].nValue = 0;
51 mtx.vout.push_back(CTxOut(
52 GetBlockSubsidy(1, Params().GetConsensus())/5,
53 Params().GetFoundersRewardScriptAtHeight(1)));
54 mtx.fOverwintered = false;
56 mtx.nVersionGroupId = 0;
58 CTransaction tx {mtx};
60 block.vtx.push_back(tx);
62 MockCValidationState state;
63 CBlockIndex indexPrev {Params().GenesisBlock()};
65 auto verifier = libzcash::ProofVerifier::Strict();
67 EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
68 EXPECT_FALSE(CheckBlock(block, state, Params(), verifier, false, false));
72 class ContextualCheckBlockTest : public ::testing::Test {
74 virtual void SetUp() {
75 SelectParams(CBaseChainParams::MAIN);
78 virtual void TearDown() {
79 // Revert to test default. No-op on mainnet params.
80 RegtestDeactivateSapling();
83 // Returns a valid but empty mutable transaction at block height 1.
84 CMutableTransaction GetFirstBlockCoinbaseTx() {
85 CMutableTransaction mtx;
89 mtx.vin[0].prevout.SetNull();
92 mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
94 // Give it a single zero-valued, always-valid output.
96 mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
97 mtx.vout[0].nValue = 0;
99 // Give it a Founder's Reward vout for height 1.
100 mtx.vout.push_back(CTxOut(
101 GetBlockSubsidy(1, Params().GetConsensus())/5,
102 Params().GetFoundersRewardScriptAtHeight(1)));
107 // Expects a height-1 block containing a given transaction to pass
108 // ContextualCheckBlock. This is used in accepting (Sprout-Sprout,
109 // Overwinter-Overwinter, ...) tests. You should not call it without
110 // calling a SCOPED_TRACE macro first to usefully label any failures.
111 void ExpectValidBlockFromTx(const CTransaction& tx) {
112 // Create a block and add the transaction to it.
114 block.vtx.push_back(tx);
116 // Set the previous block index to the genesis block.
117 CBlockIndex indexPrev {Params().GenesisBlock()};
119 // We now expect this to be a valid block.
120 MockCValidationState state;
121 EXPECT_TRUE(ContextualCheckBlock(block, state, Params(), &indexPrev));
124 // Expects a height-1 block containing a given transaction to fail
125 // ContextualCheckBlock. This is used in rejecting (Sprout-Overwinter,
126 // Overwinter-Sprout, ...) tests. You should not call it without
127 // calling a SCOPED_TRACE macro first to usefully label any failures.
128 void ExpectInvalidBlockFromTx(const CTransaction& tx, int level, std::string reason) {
129 // Create a block and add the transaction to it.
131 block.vtx.push_back(tx);
133 // Set the previous block index to the genesis block.
134 CBlockIndex indexPrev {Params().GenesisBlock()};
136 // We now expect this to be an invalid block, for the given reason.
137 MockCValidationState state;
138 EXPECT_CALL(state, DoS(level, false, REJECT_INVALID, reason, false)).Times(1);
139 EXPECT_FALSE(ContextualCheckBlock(block, state, Params(), &indexPrev));
145 TEST_F(ContextualCheckBlockTest, BadCoinbaseHeight) {
146 // Put a transaction in a block with no height in scriptSig
147 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
148 mtx.vin[0].scriptSig = CScript() << OP_0;
149 mtx.vout.pop_back(); // remove the FR output
152 block.vtx.push_back(mtx);
154 // Treating block as genesis should pass
155 MockCValidationState state;
156 EXPECT_TRUE(ContextualCheckBlock(block, state, Params(), NULL));
158 // Give the transaction a Founder's Reward vout
159 mtx.vout.push_back(CTxOut(
160 GetBlockSubsidy(1, Params().GetConsensus())/5,
161 Params().GetFoundersRewardScriptAtHeight(1)));
163 // Treating block as non-genesis should fail
164 CTransaction tx2 {mtx};
167 CBlockIndex indexPrev {prev};
168 indexPrev.SetHeight(0);
169 EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1);
170 EXPECT_FALSE(ContextualCheckBlock(block, state, Params(), &indexPrev));
172 // Setting to an incorrect height should fail
173 mtx.vin[0].scriptSig = CScript() << 2 << OP_0;
174 CTransaction tx3 {mtx};
176 EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1);
177 EXPECT_FALSE(ContextualCheckBlock(block, state, Params(), &indexPrev));
179 // After correcting the scriptSig, should pass
180 mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
181 CTransaction tx4 {mtx};
183 EXPECT_TRUE(ContextualCheckBlock(block, state, Params(), &indexPrev));
186 // TEST PLAN: first, check that each ruleset accepts its own transaction type.
187 // Currently (May 2018) this means we'll test Sprout-Sprout,
188 // Overwinter-Overwinter, and Sapling-Sapling.
190 // Test block evaluated under Sprout rules will accept Sprout transactions.
191 // This test assumes that mainnet Overwinter activation is at least height 2.
192 TEST_F(ContextualCheckBlockTest, BlockSproutRulesAcceptSproutTx) {
193 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
195 // Make it a Sprout transaction w/o JoinSplits
196 mtx.fOverwintered = false;
199 SCOPED_TRACE("BlockSproutRulesAcceptSproutTx");
200 ExpectValidBlockFromTx(CTransaction(mtx));
204 // Test block evaluated under Overwinter rules will accept Overwinter transactions.
205 TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesAcceptOverwinterTx) {
206 SelectParams(CBaseChainParams::REGTEST);
207 UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
209 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
211 // Make it an Overwinter transaction
212 mtx.fOverwintered = true;
213 mtx.nVersion = OVERWINTER_TX_VERSION;
214 mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
216 SCOPED_TRACE("BlockOverwinterRulesAcceptOverwinterTx");
217 ExpectValidBlockFromTx(CTransaction(mtx));
221 // Test that a block evaluated under Sapling rules can contain Sapling transactions.
222 TEST_F(ContextualCheckBlockTest, BlockSaplingRulesAcceptSaplingTx) {
223 SelectParams(CBaseChainParams::REGTEST);
224 UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
225 UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
227 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
229 // Make it a Sapling transaction
230 mtx.fOverwintered = true;
231 mtx.nVersion = SAPLING_TX_VERSION;
232 mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
234 SCOPED_TRACE("BlockSaplingRulesAcceptSaplingTx");
235 ExpectValidBlockFromTx(CTransaction(mtx));
238 // TEST PLAN: next, check that each ruleset will not accept other transaction
239 // types. Currently (May 2018) this means we'll test Sprout-Overwinter,
240 // Sprout-Sapling, Overwinter-Sprout, Overwinter-Sapling, Sapling-Sprout, and
241 // Sapling-Overwinter.
243 // Test that a block evaluated under Sprout rules cannot contain non-Sprout
244 // transactions which require Overwinter to be active. This test assumes that
245 // mainnet Overwinter activation is at least height 2.
246 TEST_F(ContextualCheckBlockTest, BlockSproutRulesRejectOtherTx) {
247 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
249 // Make it an Overwinter transaction
250 mtx.fOverwintered = true;
251 mtx.nVersion = OVERWINTER_TX_VERSION;
252 mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
255 SCOPED_TRACE("BlockSproutRulesRejectOverwinterTx");
256 ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "tx-overwinter-not-active");
259 // Make it a Sapling transaction
260 mtx.fOverwintered = true;
261 mtx.nVersion = SAPLING_TX_VERSION;
262 mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
265 SCOPED_TRACE("BlockSproutRulesRejectSaplingTx");
266 ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "tx-overwinter-not-active");
271 // Test block evaluated under Overwinter rules cannot contain non-Overwinter
273 TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesRejectOtherTx) {
274 SelectParams(CBaseChainParams::REGTEST);
275 UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
277 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
279 // Set the version to Sprout+JoinSplit (but nJoinSplit will be 0).
283 SCOPED_TRACE("BlockOverwinterRulesRejectSproutTx");
284 ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "tx-overwinter-active");
287 // Make it a Sapling transaction
288 mtx.fOverwintered = true;
289 mtx.nVersion = SAPLING_TX_VERSION;
290 mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
293 SCOPED_TRACE("BlockOverwinterRulesRejectSaplingTx");
294 ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "bad-overwinter-tx-version-group-id");
299 // Test block evaluated under Sapling rules cannot contain non-Sapling transactions.
300 TEST_F(ContextualCheckBlockTest, BlockSaplingRulesRejectOtherTx) {
301 SelectParams(CBaseChainParams::REGTEST);
302 UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
303 UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
305 CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
307 // Set the version to Sprout+JoinSplit (but nJoinSplit will be 0).
311 SCOPED_TRACE("BlockSaplingRulesRejectSproutTx");
312 ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "tx-overwinter-active");
315 // Make it an Overwinter transaction
316 mtx.fOverwintered = true;
317 mtx.nVersion = OVERWINTER_TX_VERSION;
318 mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
321 SCOPED_TRACE("BlockSaplingRulesRejectOverwinterTx");
322 ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "bad-sapling-tx-version-group-id");