Skip to content

Commit

Permalink
Auto merge of #4025 - bitcartel:shorter_block_target_interval_zip208,…
Browse files Browse the repository at this point in the history
… r=<try>

Implement ZIP 208: Shorter Block Target Spacing

Closes #3690.
  • Loading branch information
zkbot committed Aug 8, 2019
2 parents c68511b + b99003c commit 0bae78c
Show file tree
Hide file tree
Showing 41 changed files with 813 additions and 429 deletions.
2 changes: 2 additions & 0 deletions qa/pull-tester/rpc-tests.sh
Expand Up @@ -75,6 +75,8 @@ testScripts=(
'p2p_node_bloom.py'
'regtest_signrawtransaction.py'
'finalsaplingroot.py'
# TODO: enable the following test when updating PROTOCOL_VERSION in version.h for Blossom
# 'shorter_block_times.py'
'sprout_sapling_migration.py'
'turnstile.py'
);
Expand Down
76 changes: 76 additions & 0 deletions qa/rpc-tests/shorter_block_times.py
@@ -0,0 +1,76 @@
#!/usr/bin/env python
# Copyright (c) 2019 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .

import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x."

from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
get_coinbase_address,
initialize_chain_clean,
start_nodes,
wait_and_assert_operationid_status,
)


class ShorterBlockTimes(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, [[
'-nuparams=5ba81b19:0', # Overwinter
'-nuparams=76b809bb:0', # Sapling
'-nuparams=2bb40e60:106', # Blossom
]] * 4)

def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)

def run_test(self):
print "Mining blocks..."
self.nodes[0].generate(101)
self.sync_all()

# Sanity-check the block height
assert_equal(self.nodes[0].getblockcount(), 101)

node0_taddr = get_coinbase_address(self.nodes[0])
node0_zaddr = self.nodes[0].z_getnewaddress('sapling')
recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}]
myopid = self.nodes[0].z_sendmany(node0_taddr, recipients, 1, Decimal('0'))
txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
assert_equal(105, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # Blossom activation - 1
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
assert_equal(10, Decimal(self.nodes[0].z_gettotalbalance()['private']))

self.nodes[0].generate(2)
self.sync_all()
print "Mining last pre-Blossom blocks"
# Activate blossom
self.nodes[1].generate(1)
self.sync_all()
# Check that we received a pre-Blossom mining reward
assert_equal(10, Decimal(self.nodes[1].getwalletinfo()['immature_balance']))

# After blossom activation the block reward will be halved
print "Mining first Blossom block"
self.nodes[1].generate(1)
self.sync_all()
# Check that we received an additional Blossom mining reward
assert_equal(15, self.nodes[1].getwalletinfo()['immature_balance'])

# Send and mine a transaction after activation
myopid = self.nodes[0].z_sendmany(node0_taddr, recipients, 1, Decimal('0'))
txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
assert_equal(147, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # height + 1 + 40
self.nodes[1].generate(1)
self.sync_all()
assert_equal(20, Decimal(self.nodes[0].z_gettotalbalance()['private']))


if __name__ == '__main__':
ShorterBlockTimes().main()
1 change: 1 addition & 0 deletions src/Makefile.am
Expand Up @@ -375,6 +375,7 @@ libbitcoin_common_a_SOURCES = \
chainparams.cpp \
coins.cpp \
compressor.cpp \
consensus/params.cpp \
consensus/upgrades.cpp \
core_read.cpp \
core_write.cpp \
Expand Down
2 changes: 1 addition & 1 deletion src/bitcoin-tx.cpp
Expand Up @@ -174,7 +174,7 @@ static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
static void MutateTxExpiry(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newExpiry = atoi64(cmdVal);
if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) {
if (newExpiry <= 0 || newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) {
throw std::runtime_error("Invalid TX expiry requested");
}
tx.nExpiryHeight = (int) newExpiry;
Expand Down
53 changes: 39 additions & 14 deletions src/chainparams.cpp
Expand Up @@ -85,7 +85,8 @@ class CMainParams : public CChainParams {
bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
consensus.fCoinbaseMustBeProtected = true;
consensus.nSubsidySlowStartInterval = 20000;
consensus.nSubsidyHalvingInterval = 840000;
consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL;
consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL;
consensus.nMajorityEnforceBlockUpgrade = 750;
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 4000;
Expand All @@ -98,7 +99,8 @@ class CMainParams : public CChainParams {
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowMaxAdjustDown = 32; // 32% adjustment down
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.nPreBlossomPowTargetSpacing = Consensus::PRE_BLOSSOM_POW_TARGET_SPACING;
consensus.nPostBlossomPowTargetSpacing = Consensus::POST_BLOSSOM_POW_TARGET_SPACING;
consensus.nPowAllowMinDifficultyBlocksAfterHeight = boost::none;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Expand Down Expand Up @@ -260,7 +262,7 @@ class CMainParams : public CChainParams {
// "t3T4WmAp6nrLkJ24iPpGeCe1fSWTPv47ASG", /* main-index: 53*/
// "t3fP6GrDM4QVwdjFhmCxGNbe7jXXXSDQ5dv", /* main-index: 54*/
};
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0));
}
};
static CMainParams mainParams;
Expand All @@ -276,7 +278,8 @@ class CTestNetParams : public CChainParams {
bip44CoinType = 1;
consensus.fCoinbaseMustBeProtected = true;
consensus.nSubsidySlowStartInterval = 20000;
consensus.nSubsidyHalvingInterval = 840000;
consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL;
consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL;
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 400;
Expand All @@ -289,7 +292,8 @@ class CTestNetParams : public CChainParams {
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowMaxAdjustDown = 32; // 32% adjustment down
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.nPreBlossomPowTargetSpacing = Consensus::PRE_BLOSSOM_POW_TARGET_SPACING;
consensus.nPostBlossomPowTargetSpacing = Consensus::POST_BLOSSOM_POW_TARGET_SPACING;
consensus.nPowAllowMinDifficultyBlocksAfterHeight = 299187;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Expand Down Expand Up @@ -392,7 +396,7 @@ class CTestNetParams : public CChainParams {
"t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4",
"t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt",
};
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0));
}
};
static CTestNetParams testNetParams;
Expand All @@ -408,7 +412,8 @@ class CRegTestParams : public CChainParams {
bip44CoinType = 1;
consensus.fCoinbaseMustBeProtected = false;
consensus.nSubsidySlowStartInterval = 0;
consensus.nSubsidyHalvingInterval = 150;
consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL;
consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_REGTEST_HALVING_INTERVAL;
consensus.nMajorityEnforceBlockUpgrade = 750;
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
Expand All @@ -421,7 +426,8 @@ class CRegTestParams : public CChainParams {
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down
consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.nPreBlossomPowTargetSpacing = Consensus::PRE_BLOSSOM_POW_TARGET_SPACING;
consensus.nPostBlossomPowTargetSpacing = Consensus::POST_BLOSSOM_POW_TARGET_SPACING;
consensus.nPowAllowMinDifficultyBlocksAfterHeight = 0;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Expand Down Expand Up @@ -492,7 +498,7 @@ class CRegTestParams : public CChainParams {

// Founders reward script expects a vector of 2-of-3 multisig addresses
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0));
}

void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight)
Expand All @@ -501,6 +507,13 @@ class CRegTestParams : public CChainParams {
consensus.vUpgrades[idx].nActivationHeight = nActivationHeight;
}

void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit)
{
consensus.nPowMaxAdjustDown = nPowMaxAdjustDown;
consensus.nPowMaxAdjustUp = nPowMaxAdjustUp;
consensus.powLimit = powLimit;
}

void SetRegTestZIP209Enabled() {
fZIP209Enabled = true;
}
Expand Down Expand Up @@ -557,18 +570,26 @@ bool SelectParamsFromCommandLine()
// Block height must be >0 and <=last founders reward block height
// Index variable i ranges from 0 - (vFoundersRewardAddress.size()-1)
std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const {
int maxHeight = consensus.GetLastFoundersRewardBlockHeight();
assert(nHeight > 0 && nHeight <= maxHeight);

size_t addressChangeInterval = (maxHeight + vFoundersRewardAddress.size()) / vFoundersRewardAddress.size();
int preBlossomMaxHeight = consensus.GetLastFoundersRewardBlockHeight(0);
// zip208
// FounderAddressAdjustedHeight(height) :=
// height, if not IsBlossomActivated(height)
// BlossomActivationHeight + floor((height - BlossomActivationHeight) / BlossomPoWTargetSpacingRatio), otherwise
bool blossomActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM);
if (blossomActive) {
int blossomActivationHeight = consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
nHeight = blossomActivationHeight + ((nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO);
}
assert(nHeight > 0 && nHeight <= preBlossomMaxHeight);
size_t addressChangeInterval = (preBlossomMaxHeight + vFoundersRewardAddress.size()) / vFoundersRewardAddress.size();
size_t i = nHeight / addressChangeInterval;
return vFoundersRewardAddress[i];
}

// Block height must be >0 and <=last founders reward block height
// The founders reward address is expected to be a multisig (P2SH) address
CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight());
assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight));

CTxDestination address = DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str());
assert(IsValidDestination(address));
Expand All @@ -587,3 +608,7 @@ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivation
{
regTestParams.UpdateNetworkUpgradeParameters(idx, nActivationHeight);
}

void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) {
regTestParams.UpdateRegtestPow(nPowMaxAdjustDown, nPowMaxAdjustUp, powLimit);
}
2 changes: 2 additions & 0 deletions src/chainparams.h
Expand Up @@ -156,4 +156,6 @@ bool SelectParamsFromCommandLine();
*/
void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight);

void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit);

#endif // BITCOIN_CHAINPARAMS_H
81 changes: 81 additions & 0 deletions src/consensus/params.cpp
@@ -0,0 +1,81 @@
// Copyright (c) 2019 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .

#include "params.h"

#include "upgrades.h"

namespace Consensus {
bool Params::NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const {
return NetworkUpgradeState(nHeight, *this, idx) == UPGRADE_ACTIVE;
}

int Params::Halving(int nHeight) const {
// zip208
// Halving(height) :=
// floor((height - SlowStartShift) / PreBlossomHalvingInterval), if not IsBlossomActivated(height)
// floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise
if (NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) {
int64_t blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
// Ideally we would say:
// halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval
// + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval;
// But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval
// would need to be treated as a rational number in order for this to work.
// Define scaledHalvings := halvings * consensusParams.nPostBlossomSubsidyHalvingInterval;
int64_t scaledHalvings = ((blossomActivationHeight - SubsidySlowStartShift()) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO)
+ (nHeight - blossomActivationHeight);
return (int) (scaledHalvings / nPostBlossomSubsidyHalvingInterval);
} else {
return (nHeight - SubsidySlowStartShift()) / nPreBlossomSubsidyHalvingInterval;
}
}

int Params::GetLastFoundersRewardBlockHeight(int nHeight) const {
// zip208
// FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 })
// Halving(h) is defined as floor(f(h)) where f is a strictly increasing rational
// function, so it's sufficient to solve for f(height) = 1 in the rationals and
// then take ceiling(height - 1).
// H := blossom activation height; SS := SubsidySlowStartShift(); R := BLOSSOM_POW_TARGET_SPACING_RATIO
// preBlossom:
// 1 = (height - SS) / preInterval
// height = preInterval + SS
// postBlossom:
// 1 = (H - SS) / preInterval + (height - H) / postInterval
// height = H + postInterval - (H - SS) * (postInterval / preInterval)
// height = H + postInterval - (H - SS) * R
// Note: This depends on R being an integer
bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM);
if (blossomActive) {
int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
// The following calculation depends on BLOSSOM_POW_TARGET_SPACING_RATIO being an integer.
return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval
- (blossomActivationHeight - SubsidySlowStartShift()) * BLOSSOM_POW_TARGET_SPACING_RATIO - 1;
} else {
return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1;
}
}

int64_t Params::PoWTargetSpacing(int nHeight) const {
// zip208
// PoWTargetSpacing(height) :=
// PreBlossomPoWTargetSpacing, if not IsBlossomActivated(height)
// PostBlossomPoWTargetSpacing, otherwise.
bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM);
return blossomActive ? nPostBlossomPowTargetSpacing : nPreBlossomPowTargetSpacing;
}

int64_t Params::AveragingWindowTimespan(int nHeight) const {
return nPowAveragingWindow * PoWTargetSpacing(nHeight);
}

int64_t Params::MinActualTimespan(int nHeight) const {
return (AveragingWindowTimespan(nHeight) * (100 - nPowMaxAdjustUp)) / 100;
}

int64_t Params::MaxActualTimespan(int nHeight) const {
return (AveragingWindowTimespan(nHeight) * (100 + nPowMaxAdjustDown)) / 100;
}
}

0 comments on commit 0bae78c

Please sign in to comment.