From 6bbe0906a8f521b436071f5c08533f3763d230c0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 30 Jun 2021 22:22:05 +0100 Subject: [PATCH] ZIP 203: Enforce coinbase nExpiryHeight consensus rule from NU5 --- src/gtest/test_checktransaction.cpp | 2 +- src/main.cpp | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index df36cb9ec..ce9944985 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -769,7 +769,7 @@ TEST(ChecktransactionTests, OverwinterExpiryHeight) { CTransaction tx(mtx); MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-expiry-height-too-high", false)).Times(1); - CheckTransactionWithoutProofVerification(tx, state); + ContextualCheckTransaction(tx, state, Params(), 1, true); } { diff --git a/src/main.cpp b/src/main.cpp index 6e2790496..dc0396e35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1136,11 +1136,25 @@ bool ContextualCheckTransaction( if (tx.IsCoinBase()) { // TODO: Check that Orchard coinbase outputs can be decrypted with the all-zeros OVK + } else { + // ZIP 203: From NU5, the upper limit on nExpiryHeight is removed for coinbase + // transactions. + if (tx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { + return state.DoS(100, error("CheckTransaction(): expiry height is too high"), + REJECT_INVALID, "bad-tx-expiry-height-too-high"); + } } } else { // Rules that apply generally before NU5. These were previously // noncontextual checks that became contextual after NU5 activation. + if (tx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { + return state.DoS( + dosLevelPotentiallyRelaxing, + error("CheckTransaction(): expiry height is too high"), + REJECT_INVALID, "bad-tx-expiry-height-too-high"); + } + // Check that Orchard transaction components are not present prior to // NU5. NOTE: This is an internal zcashd consistency check; it does not // correspond to a consensus rule in the protocol specification, but is @@ -1406,10 +1420,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio return state.DoS(100, error("CheckTransaction(): unknown tx version group id"), REJECT_INVALID, "bad-tx-version-group-id"); } - if (tx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { - return state.DoS(100, error("CheckTransaction(): expiry height is too high"), - REJECT_INVALID, "bad-tx-expiry-height-too-high"); - } } auto orchard_bundle = tx.GetOrchardBundle(); @@ -4673,6 +4683,15 @@ bool ContextualCheckBlock( } } + // ZIP 203: From NU5 onwards, nExpiryHeight is set to the block height in coinbase + // transactions. + if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5)) { + if (block.vtx[0].nExpiryHeight != nHeight) { + return state.DoS(100, error("%s: block height mismatch in nExpiryHeight", __func__), + REJECT_INVALID, "bad-cb-height"); + } + } + if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY)) { // Funding streams are checked inside ContextualCheckTransaction. // This empty conditional branch exists to enforce this ZIP 207 consensus rule: