diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 7adeda3dd..dc14dd7c7 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -82,6 +82,7 @@ testScripts=( 'sprout_sapling_migration.py' 'turnstile.py' 'mining_shielded_coinbase.py' + 'coinbase_funding_streams.py' 'framework.py' 'sapling_rewind_check.py' 'feature_zip221.py' diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py index f024cc07e..cea3267e8 100755 --- a/qa/rpc-tests/blockchain.py +++ b/qa/rpc-tests/blockchain.py @@ -40,11 +40,11 @@ class BlockchainTest(BitcoinTestFramework): node = self.nodes[0] res = node.gettxoutsetinfo() - assert_equal(res['total_amount'], decimal.Decimal('2181.25000000')) # 150*12.5 + 49*6.25 + assert_equal(res['total_amount'], decimal.Decimal('2143.75000000')) # 144*12.5 + 55*6.25 assert_equal(res['transactions'], 200) assert_equal(res['height'], 200) - assert_equal(res['txouts'], 349) # 150*2 + 49 - assert_equal(res['bytes_serialized'], 14951), # 32*199 + 48*90 + 49*60 + 27*49 + assert_equal(res['txouts'], 343) # 144*2 + 55 + assert_equal(res['bytes_serialized'], 14819), # 32*199 + 48*90 + 49*54 + 27*55 assert_equal(len(res['bestblock']), 64) assert_equal(len(res['hash_serialized']), 64) diff --git a/qa/rpc-tests/coinbase_funding_streams.py b/qa/rpc-tests/coinbase_funding_streams.py new file mode 100755 index 000000000..31c081e90 --- /dev/null +++ b/qa/rpc-tests/coinbase_funding_streams.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://www.opensource.org/licenses/mit-license.php . + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.mininode import ( + nuparams, + fundingstream, +) +from test_framework.util import ( + assert_equal, + bitcoind_processes, + connect_nodes, + initialize_chain_clean, + start_node, + BLOSSOM_BRANCH_ID, + HEARTWOOD_BRANCH_ID, + CANOPY_BRANCH_ID, +) + +class CoinbaseFundingStreamsTest (BitcoinTestFramework): + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def start_node_with(self, index, extra_args=[]): + args = [ + nuparams(BLOSSOM_BRANCH_ID, 1), + nuparams(HEARTWOOD_BRANCH_ID, 2), + nuparams(CANOPY_BRANCH_ID, 5), + "-nurejectoldversions=false", + ] + return start_node(index, self.options.tmpdir, args + extra_args) + + def setup_network(self, split=False): + self.nodes = [] + self.nodes.append(self.start_node_with(0)) + self.nodes.append(self.start_node_with(1)) + connect_nodes(self.nodes[1], 0) + self.is_network_split=False + self.sync_all() + + def run_test (self): + # Generate a shielded address for node 1 for miner rewards, + miner_addr = self.nodes[1].z_getnewaddress('sapling') + + # Generate a shielded address (belonging to node 0) for funding stream + # rewards. + fs_addr = self.nodes[0].z_getnewaddress('sapling') + + # Generate past heartwood activation we won't need node 1 from this + # point onward except to check miner reward balances + self.nodes[1].generate(2) + self.sync_all() + + # Restart node 0 with funding streams. + self.nodes[0].stop() + bitcoind_processes[0].wait() + self.nodes[0] = self.start_node_with(0, [ + "-mineraddress=%s" % miner_addr, + "-minetolocalwallet=0", + fundingstream(0, 5, 9, [fs_addr, fs_addr, fs_addr]), + fundingstream(1, 5, 9, [fs_addr, fs_addr, fs_addr]), + fundingstream(2, 5, 9, [fs_addr, fs_addr, fs_addr]), + ]) + connect_nodes(self.nodes[1], 0) + self.sync_all() + + print("Generate to just prior to Canopy activation") + self.nodes[0].generate(2) + self.sync_all() + + # All miner addresses belong to node 1; check balances + walletinfo = self.nodes[1].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 10) + assert_equal(walletinfo['balance'], 0) + assert_equal(self.nodes[1].z_getbalance(miner_addr, 0), 10) + assert_equal(self.nodes[1].z_getbalance(miner_addr), 10) + + print("Activating Canopy") + self.nodes[0].generate(4) + self.sync_all() + + # check that miner payments made it to node 1's wallet + walletinfo = self.nodes[1].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 10) + assert_equal(walletinfo['balance'], 0) + assert_equal(self.nodes[1].z_getbalance(miner_addr, 0), 30) + assert_equal(self.nodes[1].z_getbalance(miner_addr), 30) + + # check that the node 0 private balance has been augmented by the + # funding stream payments + assert_equal(self.nodes[0].z_getbalance(fs_addr, 0), 5) + assert_equal(self.nodes[0].z_getbalance(fs_addr), 5) + assert_equal(self.nodes[0].z_gettotalbalance()['private'], '5.00') + assert_equal(self.nodes[0].z_gettotalbalance()['total'], '5.00') + +if __name__ == '__main__': + CoinbaseFundingStreamsTest().main() + diff --git a/qa/rpc-tests/mining_shielded_coinbase.py b/qa/rpc-tests/mining_shielded_coinbase.py index 64b73c772..bef3493be 100755 --- a/qa/rpc-tests/mining_shielded_coinbase.py +++ b/qa/rpc-tests/mining_shielded_coinbase.py @@ -6,7 +6,10 @@ from decimal import Decimal from test_framework.authproxy import JSONRPCException from test_framework.test_framework import BitcoinTestFramework +from test_framework.mininode import nuparams from test_framework.util import ( + BLOSSOM_BRANCH_ID, + HEARTWOOD_BRANCH_ID, assert_equal, assert_raises, bitcoind_processes, @@ -25,8 +28,8 @@ class ShieldCoinbaseTest (BitcoinTestFramework): def start_node_with(self, index, extra_args=[]): args = [ - "-nuparams=2bb40e60:1", # Blossom - "-nuparams=f5b9230b:10", # Heartwood + nuparams(BLOSSOM_BRANCH_ID, 1), + nuparams(HEARTWOOD_BRANCH_ID, 10), "-nurejectoldversions=false", ] return start_node(index, self.options.tmpdir, args + extra_args) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 32eceeb79..ca55f6d9b 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -80,6 +80,9 @@ def hash256(s): def nuparams(branch_id, height): return '-nuparams=%x:%d' % (branch_id, height) +def fundingstream(idx, start_height, end_height, addrs): + return '-fundingstream=%d:%d:%d:%s' % (idx, start_height, end_height, ",".join(addrs)) + def ser_compactsize(n): if n < 253: return struct.pack("B", n) diff --git a/src/Makefile.am b/src/Makefile.am index 3b911af92..a86943e80 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -181,6 +181,7 @@ BITCOIN_CORE_H = \ compat/sanity.h \ compressor.h \ consensus/consensus.h \ + consensus/funding.h \ consensus/params.h \ consensus/upgrades.h \ consensus/validation.h \ @@ -413,6 +414,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ compressor.cpp \ + consensus/funding.cpp \ consensus/params.cpp \ consensus/upgrades.cpp \ core_read.cpp \ diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 1bb304596..473ad3f1c 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -240,9 +240,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn if (!ParseMoney(strValue, value)) throw std::runtime_error("invalid TX output value"); + KeyIO keyIO(Params()); + // extract and validate ADDRESS std::string strAddr = strInput.substr(pos + 1, std::string::npos); - CTxDestination destination = DecodeDestination(strAddr); + CTxDestination destination = keyIO.DecodeDestination(strAddr); if (!IsValidDestination(destination)) { throw std::runtime_error("invalid TX output address"); } @@ -399,10 +401,12 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput) UniValue keysObj = registers["privatekeys"]; fGivenKeys = true; + KeyIO keyIO(Params()); + for (size_t kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) throw std::runtime_error("privatekey not a std::string"); - CKey key = DecodeSecret(keysObj[kidx].getValStr()); + CKey key = keyIO.DecodeSecret(keysObj[kidx].getValStr()); if (!key.IsValid()) { throw std::runtime_error("privatekey not valid"); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index cd53f0730..39e2b0a65 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Zcash Developers // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php . @@ -87,7 +88,7 @@ public: consensus.fCoinbaseMustBeShielded = true; consensus.nSubsidySlowStartInterval = 20000; consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL; - consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL; + consensus.nPostBlossomSubsidyHalvingInterval = POST_BLOSSOM_HALVING_INTERVAL(Consensus::PRE_BLOSSOM_HALVING_INTERVAL); consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 4000; @@ -125,6 +126,50 @@ public: consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.nFundingPeriodLength = consensus.nPostBlossomSubsidyHalvingInterval / 48; + + // guarantees the first 2 characters, when base58 encoded, are "t1" + keyConstants.base58Prefixes[PUBKEY_ADDRESS] = {0x1C,0xB8}; + // guarantees the first 2 characters, when base58 encoded, are "t3" + keyConstants.base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBD}; + // the first character, when base58 encoded, is "5" or "K" or "L" (as in Bitcoin) + keyConstants.base58Prefixes[SECRET_KEY] = {0x80}; + // do not rely on these BIP32 prefixes; they are not specified and may change + keyConstants.base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x88,0xB2,0x1E}; + keyConstants.base58Prefixes[EXT_SECRET_KEY] = {0x04,0x88,0xAD,0xE4}; + // guarantees the first 2 characters, when base58 encoded, are "zc" + keyConstants.base58Prefixes[ZCPAYMENT_ADDRESS] = {0x16,0x9A}; + // guarantees the first 4 characters, when base58 encoded, are "ZiVK" + keyConstants.base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAB,0xD3}; + // guarantees the first 2 characters, when base58 encoded, are "SK" + keyConstants.base58Prefixes[ZCSPENDING_KEY] = {0xAB,0x36}; + + keyConstants.bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs"; + keyConstants.bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews"; + keyConstants.bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; + keyConstants.bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; + keyConstants.bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviews"; + + // TODO: This `if` can be removed once canopy activation height is set. + if (consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + std::vector addresses(48, ""); + consensus.AddZIP207FundingStream( + keyConstants, + Consensus::FS_ZIP214_ECC, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + consensus.AddZIP207FundingStream( + keyConstants, + Consensus::FS_ZIP214_ZF, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + consensus.AddZIP207FundingStream( + keyConstants, + Consensus::FS_ZIP214_MG, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + } + // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("000000000000000000000000000000000000000000000000017e73a331fae01c"); @@ -155,28 +200,6 @@ public: vSeeds.push_back(CDNSSeedData("zfnd.org", "mainnet.seeder.zfnd.org")); // Zcash Foundation vSeeds.push_back(CDNSSeedData("yolo.money", "mainnet.is.yolo.money")); // gtank - // guarantees the first 2 characters, when base58 encoded, are "t1" - base58Prefixes[PUBKEY_ADDRESS] = {0x1C,0xB8}; - // guarantees the first 2 characters, when base58 encoded, are "t3" - base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBD}; - // the first character, when base58 encoded, is "5" or "K" or "L" (as in Bitcoin) - base58Prefixes[SECRET_KEY] = {0x80}; - // do not rely on these BIP32 prefixes; they are not specified and may change - base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x88,0xB2,0x1E}; - base58Prefixes[EXT_SECRET_KEY] = {0x04,0x88,0xAD,0xE4}; - // guarantees the first 2 characters, when base58 encoded, are "zc" - base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0x9A}; - // guarantees the first 4 characters, when base58 encoded, are "ZiVK" - base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAB,0xD3}; - // guarantees the first 2 characters, when base58 encoded, are "SK" - base58Prefixes[ZCSPENDING_KEY] = {0xAB,0x36}; - - bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs"; - bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews"; - bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; - bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; - bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviews"; - vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); fMiningRequiresPeers = true; @@ -290,7 +313,7 @@ public: consensus.fCoinbaseMustBeShielded = true; consensus.nSubsidySlowStartInterval = 20000; consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL; - consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL; + consensus.nPostBlossomSubsidyHalvingInterval = POST_BLOSSOM_HALVING_INTERVAL(Consensus::PRE_BLOSSOM_HALVING_INTERVAL); consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 400; @@ -332,6 +355,50 @@ public: consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.nFundingPeriodLength = consensus.nPostBlossomSubsidyHalvingInterval / 48; + + // guarantees the first 2 characters, when base58 encoded, are "tm" + keyConstants.base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; + // guarantees the first 2 characters, when base58 encoded, are "t2" + keyConstants.base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; + // the first character, when base58 encoded, is "9" or "c" (as in Bitcoin) + keyConstants.base58Prefixes[SECRET_KEY] = {0xEF}; + // do not rely on these BIP32 prefixes; they are not specified and may change + keyConstants.base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; + keyConstants.base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; + // guarantees the first 2 characters, when base58 encoded, are "zt" + keyConstants.base58Prefixes[ZCPAYMENT_ADDRESS] = {0x16,0xB6}; + // guarantees the first 4 characters, when base58 encoded, are "ZiVt" + keyConstants.base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; + // guarantees the first 2 characters, when base58 encoded, are "ST" + keyConstants.base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; + + keyConstants.bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling"; + keyConstants.bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling"; + keyConstants.bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; + keyConstants.bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; + keyConstants.bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewtestsapling"; + + // TODO: This `if` can be removed once canopy activation height is set. + if (consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + std::vector addresses(48, ""); + consensus.AddZIP207FundingStream( + keyConstants, + Consensus::FS_ZIP214_ECC, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + consensus.AddZIP207FundingStream( + keyConstants, + Consensus::FS_ZIP214_ZF, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + consensus.AddZIP207FundingStream( + keyConstants, + Consensus::FS_ZIP214_MG, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + } + // On testnet we activate this rule 6 blocks after Blossom activation. From block 299188 and // prior to Blossom activation, the testnet minimum-difficulty threshold was 15 minutes (i.e. // a minimum difficulty block can be mined if no block is mined normally within 15 minutes): @@ -375,28 +442,6 @@ public: vSeeds.push_back(CDNSSeedData("zfnd.org", "testnet.seeder.zfnd.org")); // Zcash Foundation vSeeds.push_back(CDNSSeedData("yolo.money", "testnet.is.yolo.money")); // gtank - // guarantees the first 2 characters, when base58 encoded, are "tm" - base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; - // guarantees the first 2 characters, when base58 encoded, are "t2" - base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; - // the first character, when base58 encoded, is "9" or "c" (as in Bitcoin) - base58Prefixes[SECRET_KEY] = {0xEF}; - // do not rely on these BIP32 prefixes; they are not specified and may change - base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; - base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; - // guarantees the first 2 characters, when base58 encoded, are "zt" - base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; - // guarantees the first 4 characters, when base58 encoded, are "ZiVt" - base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; - // guarantees the first 2 characters, when base58 encoded, are "ST" - base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; - - bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling"; - bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling"; - bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; - bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; - bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewtestsapling"; - vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); fMiningRequiresPeers = true; @@ -456,7 +501,7 @@ public: consensus.fCoinbaseMustBeShielded = false; consensus.nSubsidySlowStartInterval = 0; consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL; - consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_REGTEST_HALVING_INTERVAL; + consensus.nPostBlossomSubsidyHalvingInterval = POST_BLOSSOM_HALVING_INTERVAL(Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL); consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; @@ -494,6 +539,26 @@ public: consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.nFundingPeriodLength = consensus.nPostBlossomSubsidyHalvingInterval / 48; + // Defined funding streams can be enabled with node config flags. + + // These prefixes are the same as the testnet prefixes + keyConstants.base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; + keyConstants.base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; + keyConstants.base58Prefixes[SECRET_KEY] = {0xEF}; + // do not rely on these BIP32 prefixes; they are not specified and may change + keyConstants.base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; + keyConstants.base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; + keyConstants.base58Prefixes[ZCPAYMENT_ADDRESS] = {0x16,0xB6}; + keyConstants.base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; + keyConstants.base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; + + keyConstants.bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling"; + keyConstants.bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling"; + keyConstants.bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling"; + keyConstants.bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest"; + keyConstants.bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewregtestsapling"; + // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00"); @@ -529,22 +594,6 @@ public: 0, 0 }; - // These prefixes are the same as the testnet prefixes - base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; - base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; - base58Prefixes[SECRET_KEY] = {0xEF}; - // do not rely on these BIP32 prefixes; they are not specified and may change - base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; - base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; - base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; - base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; - base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; - - bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling"; - bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling"; - bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling"; - bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest"; - bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewregtestsapling"; // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" }; @@ -557,6 +606,12 @@ public: consensus.vUpgrades[idx].nActivationHeight = nActivationHeight; } + void UpdateFundingStreamParameters(Consensus::FundingStreamIndex idx, Consensus::FundingStream fs) + { + assert(idx >= Consensus::FIRST_FUNDING_STREAM && idx < Consensus::MAX_FUNDING_STREAMS); + consensus.vFundingStreams[idx] = fs; + } + void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) { consensus.nPowMaxAdjustDown = nPowMaxAdjustDown; @@ -630,7 +685,8 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const { assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight)); - CTxDestination address = DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str()); + KeyIO keyIO(*this); + CTxDestination address = keyIO.DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str()); assert(IsValidDestination(address)); assert(IsScriptDestination(address)); CScriptID scriptID = boost::get(address); // address is a boost variant @@ -648,6 +704,11 @@ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivation regTestParams.UpdateNetworkUpgradeParameters(idx, nActivationHeight); } +void UpdateFundingStreamParameters(Consensus::FundingStreamIndex idx, Consensus::FundingStream fs) +{ + regTestParams.UpdateFundingStreamParameters(idx, fs); +} + void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) { regTestParams.UpdateRegtestPow(nPowMaxAdjustDown, nPowMaxAdjustUp, powLimit); } diff --git a/src/chainparams.h b/src/chainparams.h index 7bb38a6ae..e38867ff5 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -32,6 +32,15 @@ struct CCheckpointData { double fTransactionsPerDay; }; +class CBaseKeyConstants : public KeyConstants { +public: + const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } + const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; } + + std::vector base58Prefixes[KeyConstants::MAX_BASE58_TYPES]; + std::string bech32HRPs[KeyConstants::MAX_BECH32_TYPES]; +}; + /** * CChainParams defines various tweakable parameters of a given instance of the * Bitcoin system. There are three: the main network on which people trade goods @@ -39,33 +48,9 @@ struct CCheckpointData { * a regression test mode which is intended for private networks only. It has * minimal difficulty to ensure that blocks can be found instantly. */ -class CChainParams +class CChainParams: public KeyConstants { public: - enum Base58Type { - PUBKEY_ADDRESS, - SCRIPT_ADDRESS, - SECRET_KEY, - EXT_PUBLIC_KEY, - EXT_SECRET_KEY, - - ZCPAYMENT_ADDRRESS, - ZCSPENDING_KEY, - ZCVIEWING_KEY, - - MAX_BASE58_TYPES - }; - - enum Bech32Type { - SAPLING_PAYMENT_ADDRESS, - SAPLING_FULL_VIEWING_KEY, - SAPLING_INCOMING_VIEWING_KEY, - SAPLING_EXTENDED_SPEND_KEY, - SAPLING_EXTENDED_FVK, - - MAX_BECH32_TYPES - }; - const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } @@ -93,8 +78,12 @@ public: /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } const std::vector& DNSSeeds() const { return vSeeds; } - const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } - const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; } + const std::vector& Base58Prefix(Base58Type type) const { + return keyConstants.Base58Prefix(type); + } + const std::string& Bech32HRP(Bech32Type type) const { + return keyConstants.Bech32HRP(type); + } const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } /** Return the founder's reward address and script for a given block height */ @@ -113,8 +102,7 @@ protected: int nDefaultPort = 0; uint64_t nPruneAfterHeight = 0; std::vector vSeeds; - std::vector base58Prefixes[MAX_BASE58_TYPES]; - std::string bech32HRPs[MAX_BECH32_TYPES]; + CBaseKeyConstants keyConstants; std::string strNetworkID; std::string strCurrencyUnits; uint32_t bip44CoinType; @@ -158,4 +146,9 @@ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivation void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit); +/** + * Allows modifying the regtest funding stream parameters. + */ +void UpdateFundingStreamParameters(Consensus::FundingStreamIndex idx, Consensus::FundingStream fs); + #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/consensus/funding.cpp b/src/consensus/funding.cpp new file mode 100644 index 000000000..79dffb631 --- /dev/null +++ b/src/consensus/funding.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2020 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#include + +namespace Consensus +{ +/** + * General information about each funding stream. + * Ordered by Consensus::FundingStreamIndex. + */ +const struct FSInfo FundingStreamInfo[Consensus::MAX_FUNDING_STREAMS] = { + { + .recipient = "Electric Coin Company", + .specification = "https://zips.z.cash/zip-0214", + .valueNumerator = 7, + .valueDenominator = 100, + }, + { + .recipient = "Zcash Foundation", + .specification = "https://zips.z.cash/zip-0214", + .valueNumerator = 5, + .valueDenominator = 100, + }, + { + .recipient = "Major Grants", + .specification = "https://zips.z.cash/zip-0214", + .valueNumerator = 8, + .valueDenominator = 100, + } +}; + +CAmount FSInfo::Value(CAmount blockSubsidy) const +{ + // Integer division is floor division for nonnegative integers in C++ + return CAmount((blockSubsidy * valueNumerator) / valueDenominator); +} + +std::set GetActiveFundingStreamElements( + int nHeight, + CAmount blockSubsidy, + const Consensus::Params& params) +{ + std::set> requiredElements; + for (uint32_t idx = Consensus::FIRST_FUNDING_STREAM; idx < Consensus::MAX_FUNDING_STREAMS; idx++) { + // The following indexed access is safe as Consensus::MAX_FUNDING_STREAMS is used + // in the definition of vFundingStreams. + auto fs = params.vFundingStreams[idx]; + // Funding period is [startHeight, endHeight) + if (fs && nHeight >= fs.get().GetStartHeight() && nHeight < fs.get().GetEndHeight()) { + requiredElements.insert(std::make_pair( + fs.get().RecipientAddress(params, nHeight), + FundingStreamInfo[idx].Value(blockSubsidy))); + } + } + return requiredElements; +}; + +std::vector GetActiveFundingStreams( + int nHeight, + const Consensus::Params& params) +{ + std::vector activeStreams; + for (uint32_t idx = Consensus::FIRST_FUNDING_STREAM; idx < Consensus::MAX_FUNDING_STREAMS; idx++) { + auto fs = params.vFundingStreams[idx]; + if (fs && nHeight >= fs.get().GetStartHeight() && nHeight < fs.get().GetEndHeight()) { + activeStreams.push_back(FundingStreamInfo[idx]); + } + } + return activeStreams; +}; + +} // namespace Consensus diff --git a/src/consensus/funding.h b/src/consensus/funding.h new file mode 100644 index 000000000..5f7b96acc --- /dev/null +++ b/src/consensus/funding.h @@ -0,0 +1,40 @@ +// Copyright (c) 2020 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#ifndef ZCASH_CONSENSUS_FUNDING_H +#define ZCASH_CONSENSUS_FUNDING_H + +#include +#include + +#include + +namespace Consensus +{ + +struct FSInfo { + std::string recipient; + std::string specification; + uint64_t valueNumerator; + uint64_t valueDenominator; + + CAmount Value(CAmount blockSubsidy) const; +}; + +extern const struct FSInfo FundingStreamInfo[]; + +typedef std::pair FundingStreamElement; + +std::set GetActiveFundingStreamElements( + int nHeight, + CAmount blockSubsidy, + const Consensus::Params& params); + +std::vector GetActiveFundingStreams( + int nHeight, + const Consensus::Params& params); + +} // namespace Consensus + +#endif // ZCASH_CONSENSUS_FUNDING_H diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 076866add..48ff3909a 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -4,6 +4,9 @@ #include "params.h" +#include +#include +#include