mirror of
https://git.hush.is/hush/hush3.git
synced 2025-09-26 00:05:12 -04:00
Adjust consensus rules to require v4 transactions from Sapling activation
This commit is contained in:
parent
0753a0e8a9
commit
987b8ee60e
@ -10,10 +10,14 @@
|
||||
static const int32_t MIN_BLOCK_VERSION = 4;
|
||||
/** The minimum allowed transaction version (network rule) */
|
||||
static const int32_t SPROUT_MIN_TX_VERSION = 1;
|
||||
/** The minimum allowed transaction version (network rule) */
|
||||
/** The minimum allowed Overwinter transaction version (network rule) */
|
||||
static const int32_t OVERWINTER_MIN_TX_VERSION = 3;
|
||||
/** The maximum allowed transaction version (network rule) */
|
||||
/** The maximum allowed Overwinter transaction version (network rule) */
|
||||
static const int32_t OVERWINTER_MAX_TX_VERSION = 3;
|
||||
/** The minimum allowed Sapling transaction version (network rule) */
|
||||
static const int32_t SAPLING_MIN_TX_VERSION = 4;
|
||||
/** The maximum allowed Sapling transaction version (network rule) */
|
||||
static const int32_t SAPLING_MAX_TX_VERSION = 4;
|
||||
/** The maximum allowed size for a serialized block, in bytes (network rule) */
|
||||
static const unsigned int MAX_BLOCK_SIZE = 2000000;
|
||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||
|
@ -110,6 +110,36 @@ TEST(ContextualCheckBlock, BadCoinbaseHeight) {
|
||||
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
}
|
||||
|
||||
|
||||
// Test that a block evaluated under Sprout rules cannot contain Sapling transactions.
|
||||
// This test assumes that mainnet Overwinter activation is at least height 2.
|
||||
TEST(ContextualCheckBlock, BlockSproutRulesRejectSaplingTx) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
mtx.vout[0].nValue = 0;
|
||||
|
||||
mtx.fOverwintered = true;
|
||||
mtx.nVersion = SAPLING_TX_VERSION;
|
||||
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
|
||||
|
||||
CTransaction tx {mtx};
|
||||
CBlock block;
|
||||
block.vtx.push_back(tx);
|
||||
|
||||
MockCValidationState state;
|
||||
CBlockIndex indexPrev {Params().GenesisBlock()};
|
||||
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
|
||||
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
}
|
||||
|
||||
|
||||
// Test that a block evaluated under Sprout rules cannot contain Overwinter transactions.
|
||||
// This test assumes that mainnet Overwinter activation is at least height 2.
|
||||
TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) {
|
||||
@ -170,6 +200,41 @@ TEST(ContextualCheckBlock, BlockSproutRulesAcceptSproutTx) {
|
||||
}
|
||||
|
||||
|
||||
// Test that a block evaluated under Overwinter rules cannot contain Sapling transactions.
|
||||
TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSaplingTx) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
|
||||
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
mtx.vout[0].nValue = 0;
|
||||
mtx.vout.push_back(CTxOut(
|
||||
GetBlockSubsidy(1, Params().GetConsensus())/5,
|
||||
Params().GetFoundersRewardScriptAtHeight(1)));
|
||||
|
||||
mtx.fOverwintered = true;
|
||||
mtx.nVersion = SAPLING_TX_VERSION;
|
||||
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
|
||||
|
||||
CTransaction tx {mtx};
|
||||
CBlock block;
|
||||
block.vtx.push_back(tx);
|
||||
|
||||
MockCValidationState state;
|
||||
CBlockIndex indexPrev {Params().GenesisBlock()};
|
||||
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-overwinter-tx-version-group-id", false)).Times(1);
|
||||
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
|
||||
// Revert to default
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
// Test block evaluated under Overwinter rules will accept Overwinter transactions
|
||||
TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
@ -202,7 +267,6 @@ TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test block evaluated under Overwinter rules will reject Sprout transactions
|
||||
TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
@ -230,4 +294,108 @@ TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) {
|
||||
|
||||
// Revert to default
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test that a block evaluated under Sapling rules can contain Sapling transactions.
|
||||
TEST(ContextualCheckBlock, BlockSaplingRulesAcceptSaplingTx) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
|
||||
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
mtx.vout[0].nValue = 0;
|
||||
mtx.vout.push_back(CTxOut(
|
||||
GetBlockSubsidy(1, Params().GetConsensus())/5,
|
||||
Params().GetFoundersRewardScriptAtHeight(1)));
|
||||
|
||||
mtx.fOverwintered = true;
|
||||
mtx.nVersion = SAPLING_TX_VERSION;
|
||||
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
|
||||
|
||||
CTransaction tx {mtx};
|
||||
CBlock block;
|
||||
block.vtx.push_back(tx);
|
||||
|
||||
MockCValidationState state;
|
||||
CBlockIndex indexPrev {Params().GenesisBlock()};
|
||||
|
||||
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
|
||||
// Revert to default
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
// Test block evaluated under Sapling rules cannot contain Overwinter transactions
|
||||
TEST(ContextualCheckBlock, BlockSaplingRulesRejectOverwinterTx) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
|
||||
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
mtx.vout[0].nValue = 0;
|
||||
mtx.vout.push_back(CTxOut(
|
||||
GetBlockSubsidy(1, Params().GetConsensus())/5,
|
||||
Params().GetFoundersRewardScriptAtHeight(1)));
|
||||
mtx.fOverwintered = true;
|
||||
mtx.nVersion = 3;
|
||||
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
|
||||
|
||||
CTransaction tx {mtx};
|
||||
CBlock block;
|
||||
block.vtx.push_back(tx);
|
||||
MockCValidationState state;
|
||||
CBlockIndex indexPrev {Params().GenesisBlock()};
|
||||
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-sapling-tx-version-group-id", false)).Times(1);
|
||||
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
|
||||
// Revert to default
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test block evaluated under Sapling rules cannot contain Sprout transactions
|
||||
TEST(ContextualCheckBlock, BlockSaplingRulesRejectSproutTx) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
|
||||
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
mtx.vout[0].nValue = 0;
|
||||
|
||||
mtx.nVersion = 2;
|
||||
|
||||
CTransaction tx {mtx};
|
||||
CBlock block;
|
||||
block.vtx.push_back(tx);
|
||||
|
||||
MockCValidationState state;
|
||||
CBlockIndex indexPrev {Params().GenesisBlock()};
|
||||
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-active", false)).Times(1);
|
||||
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
|
||||
// Revert to default
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
}
|
||||
|
44
src/main.cpp
44
src/main.cpp
@ -866,8 +866,9 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||
*/
|
||||
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const int nHeight, const int dosLevel)
|
||||
{
|
||||
bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
|
||||
bool isSprout = !isOverwinter;
|
||||
bool overwinterActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
|
||||
bool saplingActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING);
|
||||
bool isSprout = !overwinterActive;
|
||||
|
||||
// If Sprout rules apply, reject transactions which are intended for Overwinter and beyond
|
||||
if (isSprout && tx.fOverwintered) {
|
||||
@ -875,20 +876,52 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
|
||||
REJECT_INVALID, "tx-overwinter-not-active");
|
||||
}
|
||||
|
||||
// If Overwinter rules apply:
|
||||
if (isOverwinter) {
|
||||
if (saplingActive) {
|
||||
// Reject transactions with valid version but missing overwintered flag
|
||||
if (tx.nVersion >= SAPLING_MIN_TX_VERSION && !tx.fOverwintered) {
|
||||
return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwintered flag must be set"),
|
||||
REJECT_INVALID, "tx-overwintered-flag-not-set");
|
||||
}
|
||||
|
||||
// Reject transactions with non-Sapling version group ID
|
||||
if (tx.fOverwintered && tx.nVersionGroupId != SAPLING_VERSION_GROUP_ID) {
|
||||
return state.DoS(dosLevel, error("CheckTransaction(): invalid Sapling tx version"),
|
||||
REJECT_INVALID, "bad-sapling-tx-version-group-id");
|
||||
}
|
||||
|
||||
// Reject transactions with invalid version
|
||||
if (tx.fOverwintered && tx.nVersion < SAPLING_MIN_TX_VERSION ) {
|
||||
return state.DoS(100, error("CheckTransaction(): Sapling version too low"),
|
||||
REJECT_INVALID, "bad-tx-sapling-version-too-low");
|
||||
}
|
||||
|
||||
// Reject transactions with invalid version
|
||||
if (tx.fOverwintered && tx.nVersion > SAPLING_MAX_TX_VERSION ) {
|
||||
return state.DoS(100, error("CheckTransaction(): Sapling version too high"),
|
||||
REJECT_INVALID, "bad-tx-sapling-version-too-high");
|
||||
}
|
||||
} else if (overwinterActive) {
|
||||
// Reject transactions with valid version but missing overwinter flag
|
||||
if (tx.nVersion >= OVERWINTER_MIN_TX_VERSION && !tx.fOverwintered) {
|
||||
return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter flag must be set"),
|
||||
REJECT_INVALID, "tx-overwinter-flag-not-set");
|
||||
}
|
||||
|
||||
// Reject transactions with non-Overwinter version group ID
|
||||
if (tx.fOverwintered && tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) {
|
||||
return state.DoS(dosLevel, error("CheckTransaction(): invalid Overwinter tx version"),
|
||||
REJECT_INVALID, "bad-overwinter-tx-version-group-id");
|
||||
}
|
||||
|
||||
// Reject transactions with invalid version
|
||||
if (tx.fOverwintered && tx.nVersion > OVERWINTER_MAX_TX_VERSION ) {
|
||||
return state.DoS(100, error("CheckTransaction(): overwinter version too high"),
|
||||
REJECT_INVALID, "bad-tx-overwinter-version-too-high");
|
||||
}
|
||||
}
|
||||
|
||||
// Rules that apply to Overwinter or later:
|
||||
if (overwinterActive) {
|
||||
// Reject transactions intended for Sprout
|
||||
if (!tx.fOverwintered) {
|
||||
return state.DoS(dosLevel, error("ContextualCheckTransaction: overwinter is active"),
|
||||
@ -988,7 +1021,8 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
||||
return state.DoS(100, error("CheckTransaction(): overwinter version too low"),
|
||||
REJECT_INVALID, "bad-tx-overwinter-version-too-low");
|
||||
}
|
||||
if (tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) {
|
||||
if (tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID &&
|
||||
tx.nVersionGroupId != SAPLING_VERSION_GROUP_ID) {
|
||||
return state.DoS(100, error("CheckTransaction(): unknown tx version group id"),
|
||||
REJECT_INVALID, "bad-tx-version-group-id");
|
||||
}
|
||||
|
@ -308,6 +308,10 @@ public:
|
||||
static constexpr uint32_t OVERWINTER_VERSION_GROUP_ID = 0x03C48270;
|
||||
static_assert(OVERWINTER_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202");
|
||||
|
||||
// Sapling version group id
|
||||
static constexpr uint32_t SAPLING_VERSION_GROUP_ID = 0x892F2085;
|
||||
static_assert(SAPLING_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202");
|
||||
|
||||
struct CMutableTransaction;
|
||||
|
||||
/** The basic transaction that is broadcasted on the network and contained in
|
||||
|
Loading…
x
Reference in New Issue
Block a user