Auto merge of #4560 - str4d:zip-207, r=nuttycom
[ZIP 207] Funding Streams + [ZIP 214] Dev Fund Recipients Closes #4554. Closes #4555.
This commit is contained in:
commit
959f5b09d0
|
@ -82,6 +82,7 @@ testScripts=(
|
||||||
'sprout_sapling_migration.py'
|
'sprout_sapling_migration.py'
|
||||||
'turnstile.py'
|
'turnstile.py'
|
||||||
'mining_shielded_coinbase.py'
|
'mining_shielded_coinbase.py'
|
||||||
|
'coinbase_funding_streams.py'
|
||||||
'framework.py'
|
'framework.py'
|
||||||
'sapling_rewind_check.py'
|
'sapling_rewind_check.py'
|
||||||
'feature_zip221.py'
|
'feature_zip221.py'
|
||||||
|
|
|
@ -40,11 +40,11 @@ class BlockchainTest(BitcoinTestFramework):
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
res = node.gettxoutsetinfo()
|
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['transactions'], 200)
|
||||||
assert_equal(res['height'], 200)
|
assert_equal(res['height'], 200)
|
||||||
assert_equal(res['txouts'], 349) # 150*2 + 49
|
assert_equal(res['txouts'], 343) # 144*2 + 55
|
||||||
assert_equal(res['bytes_serialized'], 14951), # 32*199 + 48*90 + 49*60 + 27*49
|
assert_equal(res['bytes_serialized'], 14819), # 32*199 + 48*90 + 49*54 + 27*55
|
||||||
assert_equal(len(res['bestblock']), 64)
|
assert_equal(len(res['bestblock']), 64)
|
||||||
assert_equal(len(res['hash_serialized']), 64)
|
assert_equal(len(res['hash_serialized']), 64)
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.mininode import nuparams
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
|
BLOSSOM_BRANCH_ID,
|
||||||
|
HEARTWOOD_BRANCH_ID,
|
||||||
assert_equal,
|
assert_equal,
|
||||||
assert_raises,
|
assert_raises,
|
||||||
bitcoind_processes,
|
bitcoind_processes,
|
||||||
|
@ -25,8 +28,8 @@ class ShieldCoinbaseTest (BitcoinTestFramework):
|
||||||
|
|
||||||
def start_node_with(self, index, extra_args=[]):
|
def start_node_with(self, index, extra_args=[]):
|
||||||
args = [
|
args = [
|
||||||
"-nuparams=2bb40e60:1", # Blossom
|
nuparams(BLOSSOM_BRANCH_ID, 1),
|
||||||
"-nuparams=f5b9230b:10", # Heartwood
|
nuparams(HEARTWOOD_BRANCH_ID, 10),
|
||||||
"-nurejectoldversions=false",
|
"-nurejectoldversions=false",
|
||||||
]
|
]
|
||||||
return start_node(index, self.options.tmpdir, args + extra_args)
|
return start_node(index, self.options.tmpdir, args + extra_args)
|
||||||
|
|
|
@ -80,6 +80,9 @@ def hash256(s):
|
||||||
def nuparams(branch_id, height):
|
def nuparams(branch_id, height):
|
||||||
return '-nuparams=%x:%d' % (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):
|
def ser_compactsize(n):
|
||||||
if n < 253:
|
if n < 253:
|
||||||
return struct.pack("B", n)
|
return struct.pack("B", n)
|
||||||
|
|
|
@ -181,6 +181,7 @@ BITCOIN_CORE_H = \
|
||||||
compat/sanity.h \
|
compat/sanity.h \
|
||||||
compressor.h \
|
compressor.h \
|
||||||
consensus/consensus.h \
|
consensus/consensus.h \
|
||||||
|
consensus/funding.h \
|
||||||
consensus/params.h \
|
consensus/params.h \
|
||||||
consensus/upgrades.h \
|
consensus/upgrades.h \
|
||||||
consensus/validation.h \
|
consensus/validation.h \
|
||||||
|
@ -413,6 +414,7 @@ libbitcoin_common_a_SOURCES = \
|
||||||
chainparams.cpp \
|
chainparams.cpp \
|
||||||
coins.cpp \
|
coins.cpp \
|
||||||
compressor.cpp \
|
compressor.cpp \
|
||||||
|
consensus/funding.cpp \
|
||||||
consensus/params.cpp \
|
consensus/params.cpp \
|
||||||
consensus/upgrades.cpp \
|
consensus/upgrades.cpp \
|
||||||
core_read.cpp \
|
core_read.cpp \
|
||||||
|
|
|
@ -240,9 +240,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
|
||||||
if (!ParseMoney(strValue, value))
|
if (!ParseMoney(strValue, value))
|
||||||
throw std::runtime_error("invalid TX output value");
|
throw std::runtime_error("invalid TX output value");
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// extract and validate ADDRESS
|
// extract and validate ADDRESS
|
||||||
std::string strAddr = strInput.substr(pos + 1, std::string::npos);
|
std::string strAddr = strInput.substr(pos + 1, std::string::npos);
|
||||||
CTxDestination destination = DecodeDestination(strAddr);
|
CTxDestination destination = keyIO.DecodeDestination(strAddr);
|
||||||
if (!IsValidDestination(destination)) {
|
if (!IsValidDestination(destination)) {
|
||||||
throw std::runtime_error("invalid TX output address");
|
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"];
|
UniValue keysObj = registers["privatekeys"];
|
||||||
fGivenKeys = true;
|
fGivenKeys = true;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
|
for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
|
||||||
if (!keysObj[kidx].isStr())
|
if (!keysObj[kidx].isStr())
|
||||||
throw std::runtime_error("privatekey not a std::string");
|
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()) {
|
if (!key.IsValid()) {
|
||||||
throw std::runtime_error("privatekey not valid");
|
throw std::runtime_error("privatekey not valid");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright (c) 2010 Satoshi Nakamoto
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
|
// Copyright (c) 2015-2020 The Zcash Developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ public:
|
||||||
consensus.fCoinbaseMustBeShielded = true;
|
consensus.fCoinbaseMustBeShielded = true;
|
||||||
consensus.nSubsidySlowStartInterval = 20000;
|
consensus.nSubsidySlowStartInterval = 20000;
|
||||||
consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL;
|
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.nMajorityEnforceBlockUpgrade = 750;
|
||||||
consensus.nMajorityRejectBlockOutdated = 950;
|
consensus.nMajorityRejectBlockOutdated = 950;
|
||||||
consensus.nMajorityWindow = 4000;
|
consensus.nMajorityWindow = 4000;
|
||||||
|
@ -125,6 +126,50 @@ public:
|
||||||
consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight =
|
consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight =
|
||||||
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
|
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<std::string> 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.
|
// The best chain should have at least this much work.
|
||||||
consensus.nMinimumChainWork = uint256S("000000000000000000000000000000000000000000000000017e73a331fae01c");
|
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("zfnd.org", "mainnet.seeder.zfnd.org")); // Zcash Foundation
|
||||||
vSeeds.push_back(CDNSSeedData("yolo.money", "mainnet.is.yolo.money")); // gtank
|
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<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
|
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
|
||||||
|
|
||||||
fMiningRequiresPeers = true;
|
fMiningRequiresPeers = true;
|
||||||
|
@ -290,7 +313,7 @@ public:
|
||||||
consensus.fCoinbaseMustBeShielded = true;
|
consensus.fCoinbaseMustBeShielded = true;
|
||||||
consensus.nSubsidySlowStartInterval = 20000;
|
consensus.nSubsidySlowStartInterval = 20000;
|
||||||
consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL;
|
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.nMajorityEnforceBlockUpgrade = 51;
|
||||||
consensus.nMajorityRejectBlockOutdated = 75;
|
consensus.nMajorityRejectBlockOutdated = 75;
|
||||||
consensus.nMajorityWindow = 400;
|
consensus.nMajorityWindow = 400;
|
||||||
|
@ -332,6 +355,50 @@ public:
|
||||||
consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight =
|
consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight =
|
||||||
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
|
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<std::string> 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
|
// 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.
|
// 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):
|
// 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("zfnd.org", "testnet.seeder.zfnd.org")); // Zcash Foundation
|
||||||
vSeeds.push_back(CDNSSeedData("yolo.money", "testnet.is.yolo.money")); // gtank
|
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<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
|
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
|
||||||
|
|
||||||
fMiningRequiresPeers = true;
|
fMiningRequiresPeers = true;
|
||||||
|
@ -456,7 +501,7 @@ public:
|
||||||
consensus.fCoinbaseMustBeShielded = false;
|
consensus.fCoinbaseMustBeShielded = false;
|
||||||
consensus.nSubsidySlowStartInterval = 0;
|
consensus.nSubsidySlowStartInterval = 0;
|
||||||
consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL;
|
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.nMajorityEnforceBlockUpgrade = 750;
|
||||||
consensus.nMajorityRejectBlockOutdated = 950;
|
consensus.nMajorityRejectBlockOutdated = 950;
|
||||||
consensus.nMajorityWindow = 1000;
|
consensus.nMajorityWindow = 1000;
|
||||||
|
@ -494,6 +539,26 @@ public:
|
||||||
consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight =
|
consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight =
|
||||||
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
|
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.
|
// The best chain should have at least this much work.
|
||||||
consensus.nMinimumChainWork = uint256S("0x00");
|
consensus.nMinimumChainWork = uint256S("0x00");
|
||||||
|
|
||||||
|
@ -529,22 +594,6 @@ public:
|
||||||
0,
|
0,
|
||||||
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
|
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||||
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
|
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
|
||||||
|
@ -557,6 +606,12 @@ public:
|
||||||
consensus.vUpgrades[idx].nActivationHeight = nActivationHeight;
|
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)
|
void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit)
|
||||||
{
|
{
|
||||||
consensus.nPowMaxAdjustDown = nPowMaxAdjustDown;
|
consensus.nPowMaxAdjustDown = nPowMaxAdjustDown;
|
||||||
|
@ -630,7 +685,8 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const {
|
||||||
CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
|
CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
|
||||||
assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight));
|
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(IsValidDestination(address));
|
||||||
assert(IsScriptDestination(address));
|
assert(IsScriptDestination(address));
|
||||||
CScriptID scriptID = boost::get<CScriptID>(address); // address is a boost variant
|
CScriptID scriptID = boost::get<CScriptID>(address); // address is a boost variant
|
||||||
|
@ -648,6 +704,11 @@ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivation
|
||||||
regTestParams.UpdateNetworkUpgradeParameters(idx, nActivationHeight);
|
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) {
|
void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) {
|
||||||
regTestParams.UpdateRegtestPow(nPowMaxAdjustDown, nPowMaxAdjustUp, powLimit);
|
regTestParams.UpdateRegtestPow(nPowMaxAdjustDown, nPowMaxAdjustUp, powLimit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,15 @@ struct CCheckpointData {
|
||||||
double fTransactionsPerDay;
|
double fTransactionsPerDay;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CBaseKeyConstants : public KeyConstants {
|
||||||
|
public:
|
||||||
|
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
|
||||||
|
const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; }
|
||||||
|
|
||||||
|
std::vector<unsigned char> base58Prefixes[KeyConstants::MAX_BASE58_TYPES];
|
||||||
|
std::string bech32HRPs[KeyConstants::MAX_BECH32_TYPES];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CChainParams defines various tweakable parameters of a given instance of the
|
* CChainParams defines various tweakable parameters of a given instance of the
|
||||||
* Bitcoin system. There are three: the main network on which people trade goods
|
* 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
|
* a regression test mode which is intended for private networks only. It has
|
||||||
* minimal difficulty to ensure that blocks can be found instantly.
|
* minimal difficulty to ensure that blocks can be found instantly.
|
||||||
*/
|
*/
|
||||||
class CChainParams
|
class CChainParams: public KeyConstants
|
||||||
{
|
{
|
||||||
public:
|
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 Consensus::Params& GetConsensus() const { return consensus; }
|
||||||
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
||||||
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
|
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
|
||||||
|
@ -93,8 +78,12 @@ public:
|
||||||
/** Return the BIP70 network string (main, test or regtest) */
|
/** Return the BIP70 network string (main, test or regtest) */
|
||||||
std::string NetworkIDString() const { return strNetworkID; }
|
std::string NetworkIDString() const { return strNetworkID; }
|
||||||
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
|
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
|
||||||
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
|
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const {
|
||||||
const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; }
|
return keyConstants.Base58Prefix(type);
|
||||||
|
}
|
||||||
|
const std::string& Bech32HRP(Bech32Type type) const {
|
||||||
|
return keyConstants.Bech32HRP(type);
|
||||||
|
}
|
||||||
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
|
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
|
||||||
const CCheckpointData& Checkpoints() const { return checkpointData; }
|
const CCheckpointData& Checkpoints() const { return checkpointData; }
|
||||||
/** Return the founder's reward address and script for a given block height */
|
/** Return the founder's reward address and script for a given block height */
|
||||||
|
@ -113,8 +102,7 @@ protected:
|
||||||
int nDefaultPort = 0;
|
int nDefaultPort = 0;
|
||||||
uint64_t nPruneAfterHeight = 0;
|
uint64_t nPruneAfterHeight = 0;
|
||||||
std::vector<CDNSSeedData> vSeeds;
|
std::vector<CDNSSeedData> vSeeds;
|
||||||
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
|
CBaseKeyConstants keyConstants;
|
||||||
std::string bech32HRPs[MAX_BECH32_TYPES];
|
|
||||||
std::string strNetworkID;
|
std::string strNetworkID;
|
||||||
std::string strCurrencyUnits;
|
std::string strCurrencyUnits;
|
||||||
uint32_t bip44CoinType;
|
uint32_t bip44CoinType;
|
||||||
|
@ -158,4 +146,9 @@ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivation
|
||||||
|
|
||||||
void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit);
|
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
|
#endif // BITCOIN_CHAINPARAMS_H
|
||||||
|
|
|
@ -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 <consensus/funding.h>
|
||||||
|
|
||||||
|
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<FundingStreamElement> GetActiveFundingStreamElements(
|
||||||
|
int nHeight,
|
||||||
|
CAmount blockSubsidy,
|
||||||
|
const Consensus::Params& params)
|
||||||
|
{
|
||||||
|
std::set<std::pair<FundingStreamAddress, CAmount>> 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<FSInfo> GetActiveFundingStreams(
|
||||||
|
int nHeight,
|
||||||
|
const Consensus::Params& params)
|
||||||
|
{
|
||||||
|
std::vector<FSInfo> 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
|
|
@ -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 <amount.h>
|
||||||
|
#include <consensus/params.h>
|
||||||
|
|
||||||
|
#include <boost/variant.hpp>
|
||||||
|
|
||||||
|
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<FundingStreamAddress, CAmount> FundingStreamElement;
|
||||||
|
|
||||||
|
std::set<FundingStreamElement> GetActiveFundingStreamElements(
|
||||||
|
int nHeight,
|
||||||
|
CAmount blockSubsidy,
|
||||||
|
const Consensus::Params& params);
|
||||||
|
|
||||||
|
std::vector<FSInfo> GetActiveFundingStreams(
|
||||||
|
int nHeight,
|
||||||
|
const Consensus::Params& params);
|
||||||
|
|
||||||
|
} // namespace Consensus
|
||||||
|
|
||||||
|
#endif // ZCASH_CONSENSUS_FUNDING_H
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
|
||||||
|
#include <amount.h>
|
||||||
|
#include <key_io.h>
|
||||||
|
#include <script/standard.h>
|
||||||
#include "upgrades.h"
|
#include "upgrades.h"
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
|
@ -36,32 +39,153 @@ namespace Consensus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Params::GetLastFoundersRewardBlockHeight(int nHeight) const {
|
/**
|
||||||
|
* This method determines the block height of the `halvingIndex`th
|
||||||
|
* halving, as known at the specified `nHeight` block height.
|
||||||
|
*
|
||||||
|
* Previous implementations of this logic were specialized to the
|
||||||
|
* first halving.
|
||||||
|
*/
|
||||||
|
int Params::HalvingHeight(int nHeight, int halvingIndex) const {
|
||||||
// zip208
|
// zip208
|
||||||
// FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 })
|
// HalvingHeight(i) := max({ height ⦂ N | Halving(height) < i }) + 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
|
// Halving(h) returns the halving index at the specified height. It is
|
||||||
// then take ceiling(height - 1).
|
// defined as floor(f(h)) where f is a strictly increasing rational
|
||||||
// H := blossom activation height; SS := SubsidySlowStartShift(); R := BLOSSOM_POW_TARGET_SPACING_RATIO
|
// function, so it's sufficient to solve for f(height) = halvingIndex
|
||||||
|
// in the rationals and then take ceiling(height).
|
||||||
|
//
|
||||||
|
// H := blossom activation height;
|
||||||
|
// SS := SubsidySlowStartShift();
|
||||||
|
// R := 1 / (postInterval / preInterval) = BLOSSOM_POW_TARGET_SPACING_RATIO
|
||||||
|
// (The following calculation depends on BLOSSOM_POW_TARGET_SPACING_RATIO being an integer.)
|
||||||
|
//
|
||||||
// preBlossom:
|
// preBlossom:
|
||||||
// 1 = (height - SS) / preInterval
|
// i = (height - SS) / preInterval
|
||||||
// height = preInterval + SS
|
// height = (preInterval * i) + SS
|
||||||
|
//
|
||||||
// postBlossom:
|
// postBlossom:
|
||||||
// 1 = (H - SS) / preInterval + (height - H) / postInterval
|
// i = (H - SS) / preInterval + (HalvingHeight(i) - H) / postInterval
|
||||||
// height = H + postInterval - (H - SS) * (postInterval / preInterval)
|
// preInterval = postInterval / R
|
||||||
// height = H + postInterval - (H - SS) * R
|
// i = (H - SS) / (postInterval / R) + (HalvingHeight(i) - H) / postInterval
|
||||||
// Note: This depends on R being an integer
|
// i = (R * (H - SS) + HalvingHeight(i) - H) / postInterval
|
||||||
bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM);
|
// postInterval * i = R * (H - SS) + HalvingHeight(i) - H
|
||||||
if (blossomActive) {
|
// HalvingHeight(i) = postInterval * i - R * (H - SS) + H
|
||||||
|
if (NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) {
|
||||||
int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
|
int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
|
||||||
// The following calculation depends on BLOSSOM_POW_TARGET_SPACING_RATIO being an integer.
|
|
||||||
return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval
|
return
|
||||||
- (blossomActivationHeight - SubsidySlowStartShift()) * BLOSSOM_POW_TARGET_SPACING_RATIO - 1;
|
(nPostBlossomSubsidyHalvingInterval * halvingIndex)
|
||||||
|
- (BLOSSOM_POW_TARGET_SPACING_RATIO * (blossomActivationHeight - SubsidySlowStartShift()))
|
||||||
|
+ blossomActivationHeight;
|
||||||
} else {
|
} else {
|
||||||
return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1;
|
return (nPreBlossomSubsidyHalvingInterval * halvingIndex) + SubsidySlowStartShift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Params::GetLastFoundersRewardBlockHeight(int nHeight) const {
|
||||||
|
return HalvingHeight(nHeight, 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Params::FundingPeriodIndex(int fundingStreamStartHeight, int nHeight) const {
|
||||||
|
int firstHalvingHeight = HalvingHeight(fundingStreamStartHeight, 1);
|
||||||
|
|
||||||
|
// If the start height of the funding period is not aligned to a multiple of the
|
||||||
|
// funding period length, the first funding period will be shorter than the
|
||||||
|
// funding period length.
|
||||||
|
auto startPeriodOffset = (fundingStreamStartHeight - firstHalvingHeight) % nFundingPeriodLength;
|
||||||
|
if (startPeriodOffset < 0) startPeriodOffset += nFundingPeriodLength; // C++ '%' is remainder, not modulus!
|
||||||
|
|
||||||
|
return (nHeight - fundingStreamStartHeight + startPeriodOffset) / nFundingPeriodLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::variant<FundingStream, FundingStreamError> FundingStream::ValidateFundingStream(
|
||||||
|
const Consensus::Params& params,
|
||||||
|
const int startHeight,
|
||||||
|
const int endHeight,
|
||||||
|
const std::vector<FundingStreamAddress>& addresses
|
||||||
|
) {
|
||||||
|
if (!params.NetworkUpgradeActive(startHeight, Consensus::UPGRADE_CANOPY)) {
|
||||||
|
return FundingStreamError::CANOPY_NOT_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endHeight < startHeight) {
|
||||||
|
return FundingStreamError::ILLEGAL_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.FundingPeriodIndex(startHeight, endHeight - 1) >= addresses.size()) {
|
||||||
|
return FundingStreamError::INSUFFICIENT_ADDRESSES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FundingStream(startHeight, endHeight, addresses);
|
||||||
|
};
|
||||||
|
|
||||||
|
class GetFundingStreamOrThrow: public boost::static_visitor<FundingStream> {
|
||||||
|
public:
|
||||||
|
FundingStream operator()(const FundingStream& fs) const {
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FundingStream operator()(const FundingStreamError& e) const {
|
||||||
|
switch (e) {
|
||||||
|
case FundingStreamError::CANOPY_NOT_ACTIVE:
|
||||||
|
throw std::runtime_error("Canopy network upgrade not active at funding stream start height.");
|
||||||
|
case FundingStreamError::ILLEGAL_RANGE:
|
||||||
|
throw std::runtime_error("Illegal start/end height combination for funding stream.");
|
||||||
|
case FundingStreamError::INSUFFICIENT_ADDRESSES:
|
||||||
|
throw std::runtime_error("Insufficient payment addresses to fully exhaust funding stream.");
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unrecognized error validating funding stream.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FundingStream FundingStream::ParseFundingStream(
|
||||||
|
const Consensus::Params& params,
|
||||||
|
const KeyConstants& keyConstants,
|
||||||
|
const int startHeight,
|
||||||
|
const int endHeight,
|
||||||
|
const std::vector<std::string>& strAddresses)
|
||||||
|
{
|
||||||
|
KeyIO keyIO(keyConstants);
|
||||||
|
|
||||||
|
// Parse the address strings into concrete types.
|
||||||
|
std::vector<FundingStreamAddress> addresses;
|
||||||
|
for (auto addr : strAddresses) {
|
||||||
|
auto taddr = keyIO.DecodeDestination(addr);
|
||||||
|
if (IsValidDestination(taddr)) {
|
||||||
|
addresses.push_back(GetScriptForDestination(taddr));
|
||||||
|
} else {
|
||||||
|
auto zaddr = keyIO.DecodePaymentAddress(addr);
|
||||||
|
// If the string is not a valid transparent or Sapling address, we will
|
||||||
|
// throw here.
|
||||||
|
|
||||||
|
addresses.push_back(boost::get<libzcash::SaplingPaymentAddress>(zaddr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto validationResult = FundingStream::ValidateFundingStream(params, startHeight, endHeight, addresses);
|
||||||
|
return boost::apply_visitor(GetFundingStreamOrThrow(), validationResult);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Params::AddZIP207FundingStream(
|
||||||
|
const KeyConstants& keyConstants,
|
||||||
|
FundingStreamIndex idx,
|
||||||
|
int startHeight,
|
||||||
|
int endHeight,
|
||||||
|
const std::vector<std::string>& strAddresses)
|
||||||
|
{
|
||||||
|
vFundingStreams[idx] = FundingStream::ParseFundingStream(*this, keyConstants, startHeight, endHeight, strAddresses);
|
||||||
|
};
|
||||||
|
|
||||||
|
FundingStreamAddress FundingStream::RecipientAddress(const Consensus::Params& params, int nHeight) const
|
||||||
|
{
|
||||||
|
auto addressIndex = params.FundingPeriodIndex(startHeight, nHeight);
|
||||||
|
|
||||||
|
assert(addressIndex >= 0 && addressIndex < addresses.size());
|
||||||
|
return addresses[addressIndex];
|
||||||
|
};
|
||||||
|
|
||||||
int64_t Params::PoWTargetSpacing(int nHeight) const {
|
int64_t Params::PoWTargetSpacing(int nHeight) const {
|
||||||
// zip208
|
// zip208
|
||||||
// PoWTargetSpacing(height) :=
|
// PoWTargetSpacing(height) :=
|
||||||
|
|
|
@ -6,12 +6,18 @@
|
||||||
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
||||||
#define BITCOIN_CONSENSUS_PARAMS_H
|
#define BITCOIN_CONSENSUS_PARAMS_H
|
||||||
|
|
||||||
|
#include <script/script.h>
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
#include "key_constants.h"
|
||||||
|
#include <zcash/address/sapling.hpp>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
|
|
||||||
|
// Early declaration to ensure it is accessible.
|
||||||
|
struct Params;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index into Params.vUpgrades and NetworkUpgradeInfo
|
* Index into Params.vUpgrades and NetworkUpgradeInfo
|
||||||
*
|
*
|
||||||
|
@ -75,16 +81,77 @@ struct NetworkUpgrade {
|
||||||
boost::optional<uint256> hashActivationBlock;
|
boost::optional<uint256> hashActivationBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef boost::variant<libzcash::SaplingPaymentAddress, CScript> FundingStreamAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index into Params.vFundingStreams.
|
||||||
|
*
|
||||||
|
* Being array indices, these MUST be numbered consecutively.
|
||||||
|
*/
|
||||||
|
enum FundingStreamIndex : uint32_t {
|
||||||
|
FS_ZIP214_ECC,
|
||||||
|
FS_ZIP214_ZF,
|
||||||
|
FS_ZIP214_MG,
|
||||||
|
MAX_FUNDING_STREAMS,
|
||||||
|
};
|
||||||
|
const auto FIRST_FUNDING_STREAM = FS_ZIP214_ECC;
|
||||||
|
|
||||||
|
enum FundingStreamError {
|
||||||
|
CANOPY_NOT_ACTIVE,
|
||||||
|
ILLEGAL_RANGE,
|
||||||
|
INSUFFICIENT_ADDRESSES,
|
||||||
|
};
|
||||||
|
|
||||||
|
class FundingStream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int startHeight;
|
||||||
|
int endHeight;
|
||||||
|
std::vector<FundingStreamAddress> addresses;
|
||||||
|
|
||||||
|
FundingStream(int startHeight, int endHeight, const std::vector<FundingStreamAddress>& addresses):
|
||||||
|
startHeight(startHeight), endHeight(endHeight), addresses(addresses) { }
|
||||||
|
public:
|
||||||
|
FundingStream(const FundingStream& fs):
|
||||||
|
startHeight(fs.startHeight), endHeight(fs.endHeight), addresses(fs.addresses) { }
|
||||||
|
|
||||||
|
static boost::variant<FundingStream, FundingStreamError> ValidateFundingStream(
|
||||||
|
const Consensus::Params& params,
|
||||||
|
const int startHeight,
|
||||||
|
const int endHeight,
|
||||||
|
const std::vector<FundingStreamAddress>& addresses
|
||||||
|
);
|
||||||
|
|
||||||
|
static FundingStream ParseFundingStream(
|
||||||
|
const Consensus::Params& params,
|
||||||
|
const KeyConstants& keyConstants,
|
||||||
|
const int startHeight,
|
||||||
|
const int endHeight,
|
||||||
|
const std::vector<std::string>& strAddresses);
|
||||||
|
|
||||||
|
int GetStartHeight() const { return startHeight; };
|
||||||
|
int GetEndHeight() const { return endHeight; };
|
||||||
|
const std::vector<FundingStreamAddress>& GetAddresses() const {
|
||||||
|
return addresses;
|
||||||
|
};
|
||||||
|
|
||||||
|
FundingStreamAddress RecipientAddress(const Params& params, int nHeight) const;
|
||||||
|
};
|
||||||
|
|
||||||
/** ZIP208 block target interval in seconds. */
|
/** ZIP208 block target interval in seconds. */
|
||||||
static const unsigned int PRE_BLOSSOM_POW_TARGET_SPACING = 150;
|
static const unsigned int PRE_BLOSSOM_POW_TARGET_SPACING = 150;
|
||||||
static const unsigned int POST_BLOSSOM_POW_TARGET_SPACING = 75;
|
static const unsigned int POST_BLOSSOM_POW_TARGET_SPACING = 75;
|
||||||
static_assert(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING, "Blossom target spacing must be less than pre-Blossom target spacing.");
|
static_assert(PRE_BLOSSOM_POW_TARGET_SPACING > POST_BLOSSOM_POW_TARGET_SPACING, "Blossom target spacing must be less than pre-Blossom target spacing.");
|
||||||
static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000;
|
static_assert(PRE_BLOSSOM_POW_TARGET_SPACING % POST_BLOSSOM_POW_TARGET_SPACING == 0, "Blossom target spacing must exactly divide pre-Blossom target spacing.");
|
||||||
static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 150;
|
|
||||||
static const int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING;
|
static const int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING;
|
||||||
static_assert(BLOSSOM_POW_TARGET_SPACING_RATIO * POST_BLOSSOM_POW_TARGET_SPACING == PRE_BLOSSOM_POW_TARGET_SPACING, "Invalid BLOSSOM_POW_TARGET_SPACING_RATIO");
|
static_assert(BLOSSOM_POW_TARGET_SPACING_RATIO * POST_BLOSSOM_POW_TARGET_SPACING == PRE_BLOSSOM_POW_TARGET_SPACING, "Invalid BLOSSOM_POW_TARGET_SPACING_RATIO");
|
||||||
static const unsigned int POST_BLOSSOM_HALVING_INTERVAL = PRE_BLOSSOM_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO;
|
|
||||||
static const unsigned int POST_BLOSSOM_REGTEST_HALVING_INTERVAL = PRE_BLOSSOM_REGTEST_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO;
|
static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000;
|
||||||
|
static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 144;
|
||||||
|
|
||||||
|
#define POST_BLOSSOM_HALVING_INTERVAL(preBlossomInterval) \
|
||||||
|
(preBlossomInterval * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters that influence chain consensus.
|
* Parameters that influence chain consensus.
|
||||||
|
@ -120,16 +187,36 @@ struct Params {
|
||||||
int nPreBlossomSubsidyHalvingInterval;
|
int nPreBlossomSubsidyHalvingInterval;
|
||||||
int nPostBlossomSubsidyHalvingInterval;
|
int nPostBlossomSubsidyHalvingInterval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify the halving index at the specified height. The result will be
|
||||||
|
* negative during the slow-start period.
|
||||||
|
*/
|
||||||
int Halving(int nHeight) const;
|
int Halving(int nHeight) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block height of the specified halving.
|
||||||
|
*/
|
||||||
|
int HalvingHeight(int nHeight, int halvingIndex) const;
|
||||||
|
|
||||||
int GetLastFoundersRewardBlockHeight(int nHeight) const;
|
int GetLastFoundersRewardBlockHeight(int nHeight) const;
|
||||||
|
|
||||||
|
int FundingPeriodIndex(int fundingStreamStartHeight, int nHeight) const;
|
||||||
|
|
||||||
/** Used to check majorities for block version upgrade */
|
/** Used to check majorities for block version upgrade */
|
||||||
int nMajorityEnforceBlockUpgrade;
|
int nMajorityEnforceBlockUpgrade;
|
||||||
int nMajorityRejectBlockOutdated;
|
int nMajorityRejectBlockOutdated;
|
||||||
int nMajorityWindow;
|
int nMajorityWindow;
|
||||||
NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES];
|
NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES];
|
||||||
|
|
||||||
|
int nFundingPeriodLength;
|
||||||
|
boost::optional<FundingStream> vFundingStreams[MAX_FUNDING_STREAMS];
|
||||||
|
void AddZIP207FundingStream(
|
||||||
|
const KeyConstants& keyConstants,
|
||||||
|
FundingStreamIndex idx,
|
||||||
|
int startHeight,
|
||||||
|
int endHeight,
|
||||||
|
const std::vector<std::string>& addresses);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default block height at which the future timestamp soft fork rule activates.
|
* Default block height at which the future timestamp soft fork rule activates.
|
||||||
*
|
*
|
||||||
|
@ -188,6 +275,7 @@ struct Params {
|
||||||
|
|
||||||
uint256 nMinimumChainWork;
|
uint256 nMinimumChainWork;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Consensus
|
} // namespace Consensus
|
||||||
|
|
||||||
#endif // BITCOIN_CONSENSUS_PARAMS_H
|
#endif // BITCOIN_CONSENSUS_PARAMS_H
|
||||||
|
|
|
@ -142,9 +142,10 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
|
||||||
out.pushKV("reqSigs", nRequired);
|
out.pushKV("reqSigs", nRequired);
|
||||||
out.pushKV("type", GetTxnOutputType(type));
|
out.pushKV("type", GetTxnOutputType(type));
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue a(UniValue::VARR);
|
UniValue a(UniValue::VARR);
|
||||||
for (const CTxDestination& addr : addresses) {
|
for (const CTxDestination& addr : addresses) {
|
||||||
a.push_back(EncodeDestination(addr));
|
a.push_back(keyIO.EncodeDestination(addr));
|
||||||
}
|
}
|
||||||
out.pushKV("addresses", a);
|
out.pushKV("addresses", a);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,9 +96,10 @@ protected:
|
||||||
mtx.vout[0].nValue = 0;
|
mtx.vout[0].nValue = 0;
|
||||||
|
|
||||||
// Give it a Founder's Reward vout for height 1.
|
// Give it a Founder's Reward vout for height 1.
|
||||||
|
auto rewardScript = Params().GetFoundersRewardScriptAtHeight(1);
|
||||||
mtx.vout.push_back(CTxOut(
|
mtx.vout.push_back(CTxOut(
|
||||||
GetBlockSubsidy(1, Params().GetConsensus())/5,
|
GetBlockSubsidy(1, Params().GetConsensus())/5,
|
||||||
Params().GetFoundersRewardScriptAtHeight(1)));
|
rewardScript));
|
||||||
|
|
||||||
return mtx;
|
return mtx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utilmoneystr.h"
|
#include "utilmoneystr.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
|
#include "consensus/funding.h"
|
||||||
|
#include "key_io.h"
|
||||||
#include "utilstrencodings.h"
|
#include "utilstrencodings.h"
|
||||||
#include "zcash/Address.hpp"
|
#include "zcash/Address.hpp"
|
||||||
#include "wallet/wallet.h"
|
#include "wallet/wallet.h"
|
||||||
|
@ -40,6 +42,7 @@ TEST(FoundersRewardTest, create_testnet_2of3multisig) {
|
||||||
pubkeys.resize(3);
|
pubkeys.resize(3);
|
||||||
CPubKey newKey;
|
CPubKey newKey;
|
||||||
std::vector<std::string> addresses;
|
std::vector<std::string> addresses;
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (int i = 0; i < numKeys; i++) {
|
for (int i = 0; i < numKeys; i++) {
|
||||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||||
pubkeys[0] = newKey;
|
pubkeys[0] = newKey;
|
||||||
|
@ -59,7 +62,7 @@ TEST(FoundersRewardTest, create_testnet_2of3multisig) {
|
||||||
pWallet->AddCScript(result);
|
pWallet->AddCScript(result);
|
||||||
pWallet->SetAddressBook(innerID, "", "receive");
|
pWallet->SetAddressBook(innerID, "", "receive");
|
||||||
|
|
||||||
std::string address = EncodeDestination(innerID);
|
std::string address = keyIO.EncodeDestination(innerID);
|
||||||
addresses.push_back(address);
|
addresses.push_back(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +102,17 @@ void checkNumberOfUniqueAddresses(int nUnique) {
|
||||||
EXPECT_EQ(addresses.size(), nUnique);
|
EXPECT_EQ(addresses.size(), nUnique);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GetMaxFundingStreamHeight(const Consensus::Params& params) {
|
||||||
|
int result = 0;
|
||||||
|
for (auto fs : params.vFundingStreams) {
|
||||||
|
if (fs && result < fs.get().GetEndHeight() - 1) {
|
||||||
|
result = fs.get().GetEndHeight() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(FoundersRewardTest, General) {
|
TEST(FoundersRewardTest, General) {
|
||||||
SelectParams(CBaseChainParams::TESTNET);
|
SelectParams(CBaseChainParams::TESTNET);
|
||||||
|
@ -125,7 +139,7 @@ TEST(FoundersRewardTest, General) {
|
||||||
EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight");
|
EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(founders_reward_test, regtest_get_last_block_blossom) {
|
TEST(FoundersRewardTest, RegtestGetLastBlockBlossom) {
|
||||||
int blossomActivationHeight = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL / 2; // = 75
|
int blossomActivationHeight = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL / 2; // = 75
|
||||||
auto params = RegtestActivateBlossom(false, blossomActivationHeight);
|
auto params = RegtestActivateBlossom(false, blossomActivationHeight);
|
||||||
int lastFRHeight = params.GetLastFoundersRewardBlockHeight(blossomActivationHeight);
|
int lastFRHeight = params.GetLastFoundersRewardBlockHeight(blossomActivationHeight);
|
||||||
|
@ -134,7 +148,7 @@ TEST(founders_reward_test, regtest_get_last_block_blossom) {
|
||||||
RegtestDeactivateBlossom();
|
RegtestDeactivateBlossom();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(founders_reward_test, mainnet_get_last_block) {
|
TEST(FoundersRewardTest, MainnetGetLastBlock) {
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
auto params = Params().GetConsensus();
|
auto params = Params().GetConsensus();
|
||||||
int lastFRHeight = GetLastFoundersRewardHeight(params);
|
int lastFRHeight = GetLastFoundersRewardHeight(params);
|
||||||
|
@ -216,3 +230,71 @@ TEST(FoundersRewardTest, PerAddressRewardTestnet) {
|
||||||
SelectParams(CBaseChainParams::TESTNET);
|
SelectParams(CBaseChainParams::TESTNET);
|
||||||
verifyNumberOfRewards();
|
verifyNumberOfRewards();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that post-Canopy, block rewards are split according to ZIP 207.
|
||||||
|
TEST(FundingStreamsRewardTest, Zip207Distribution) {
|
||||||
|
auto consensus = RegtestActivateCanopy(false, 200);
|
||||||
|
|
||||||
|
int minHeight = GetLastFoundersRewardHeight(consensus) + 1;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
auto sk = libzcash::SaplingSpendingKey(uint256());
|
||||||
|
for (int idx = Consensus::FIRST_FUNDING_STREAM; idx < Consensus::MAX_FUNDING_STREAMS; idx++) {
|
||||||
|
// we can just use the same addresses for all streams, all we're trying to do here
|
||||||
|
// is validate that the streams add up to the 20% of block reward.
|
||||||
|
auto shieldedAddr = keyIO.EncodePaymentAddress(sk.default_address());
|
||||||
|
UpdateFundingStreamParameters(
|
||||||
|
(Consensus::FundingStreamIndex) idx,
|
||||||
|
Consensus::FundingStream::ParseFundingStream(
|
||||||
|
consensus,
|
||||||
|
Params(),
|
||||||
|
minHeight,
|
||||||
|
minHeight + 12,
|
||||||
|
{
|
||||||
|
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi",
|
||||||
|
shieldedAddr,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxHeight = GetMaxFundingStreamHeight(consensus);
|
||||||
|
std::map<std::string, CAmount> ms;
|
||||||
|
for (int nHeight = minHeight; nHeight <= maxHeight; nHeight++) {
|
||||||
|
auto blockSubsidy = GetBlockSubsidy(nHeight, consensus);
|
||||||
|
auto elems = GetActiveFundingStreamElements(nHeight, blockSubsidy, consensus);
|
||||||
|
|
||||||
|
CAmount totalFunding = 0;
|
||||||
|
for (Consensus::FundingStreamElement elem : elems) {
|
||||||
|
totalFunding += elem.second;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(totalFunding, blockSubsidy / 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegtestDeactivateCanopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FundingStreamsRewardTest, ParseFundingStream) {
|
||||||
|
auto consensus = RegtestActivateCanopy(false, 200);
|
||||||
|
|
||||||
|
int minHeight = GetLastFoundersRewardHeight(consensus) + 1;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
auto sk = libzcash::SaplingSpendingKey(uint256());
|
||||||
|
auto shieldedAddr = keyIO.EncodePaymentAddress(sk.default_address());
|
||||||
|
ASSERT_THROW(
|
||||||
|
Consensus::FundingStream::ParseFundingStream(
|
||||||
|
consensus,
|
||||||
|
Params(),
|
||||||
|
minHeight,
|
||||||
|
minHeight + 13,
|
||||||
|
{
|
||||||
|
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi",
|
||||||
|
shieldedAddr,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
std::runtime_error
|
||||||
|
);
|
||||||
|
|
||||||
|
RegtestDeactivateCanopy();
|
||||||
|
}
|
||||||
|
|
|
@ -9,18 +9,19 @@
|
||||||
TEST(Keys, EncodeAndDecodeSapling)
|
TEST(Keys, EncodeAndDecodeSapling)
|
||||||
{
|
{
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
auto m = GetTestMasterSaplingSpendingKey();
|
auto m = GetTestMasterSaplingSpendingKey();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 1000; i++) {
|
for (uint32_t i = 0; i < 1000; i++) {
|
||||||
auto sk = m.Derive(i);
|
auto sk = m.Derive(i);
|
||||||
{
|
{
|
||||||
std::string sk_string = EncodeSpendingKey(sk);
|
std::string sk_string = keyIO.EncodeSpendingKey(sk);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
sk_string.substr(0, 24),
|
sk_string.substr(0, 24),
|
||||||
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY));
|
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY));
|
||||||
|
|
||||||
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string);
|
||||||
EXPECT_TRUE(IsValidSpendingKey(spendingkey2));
|
EXPECT_TRUE(IsValidSpendingKey(spendingkey2));
|
||||||
|
|
||||||
ASSERT_TRUE(boost::get<libzcash::SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
ASSERT_TRUE(boost::get<libzcash::SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
||||||
|
@ -29,12 +30,12 @@ TEST(Keys, EncodeAndDecodeSapling)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto extfvk = sk.ToXFVK();
|
auto extfvk = sk.ToXFVK();
|
||||||
std::string vk_string = EncodeViewingKey(extfvk);
|
std::string vk_string = keyIO.EncodeViewingKey(extfvk);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
vk_string.substr(0, 7),
|
vk_string.substr(0, 7),
|
||||||
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK));
|
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK));
|
||||||
|
|
||||||
auto viewingkey2 = DecodeViewingKey(vk_string);
|
auto viewingkey2 = keyIO.DecodeViewingKey(vk_string);
|
||||||
EXPECT_TRUE(IsValidViewingKey(viewingkey2));
|
EXPECT_TRUE(IsValidViewingKey(viewingkey2));
|
||||||
|
|
||||||
ASSERT_TRUE(boost::get<libzcash::SaplingExtendedFullViewingKey>(&viewingkey2) != nullptr);
|
ASSERT_TRUE(boost::get<libzcash::SaplingExtendedFullViewingKey>(&viewingkey2) != nullptr);
|
||||||
|
@ -44,12 +45,12 @@ TEST(Keys, EncodeAndDecodeSapling)
|
||||||
{
|
{
|
||||||
auto addr = sk.DefaultAddress();
|
auto addr = sk.DefaultAddress();
|
||||||
|
|
||||||
std::string addr_string = EncodePaymentAddress(addr);
|
std::string addr_string = keyIO.EncodePaymentAddress(addr);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
addr_string.substr(0, 2),
|
addr_string.substr(0, 2),
|
||||||
Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS));
|
Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS));
|
||||||
|
|
||||||
auto paymentaddr2 = DecodePaymentAddress(addr_string);
|
auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string);
|
||||||
EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2));
|
EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2));
|
||||||
|
|
||||||
ASSERT_TRUE(boost::get<libzcash::SaplingPaymentAddress>(&paymentaddr2) != nullptr);
|
ASSERT_TRUE(boost::get<libzcash::SaplingPaymentAddress>(&paymentaddr2) != nullptr);
|
||||||
|
|
51
src/init.cpp
51
src/init.cpp
|
@ -439,6 +439,9 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||||
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
|
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
|
||||||
strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)");
|
strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)");
|
||||||
strUsage += HelpMessageOpt("-nurejectoldversions", strprintf("Reject peers that don't know about the current epoch (regtest-only) (default: %u)", DEFAULT_NU_REJECT_OLD_VERSIONS));
|
strUsage += HelpMessageOpt("-nurejectoldversions", strprintf("Reject peers that don't know about the current epoch (regtest-only) (default: %u)", DEFAULT_NU_REJECT_OLD_VERSIONS));
|
||||||
|
strUsage += HelpMessageOpt(
|
||||||
|
"-fundingstream=streamId:startHeight:endHeight:comma_delimited_addresses",
|
||||||
|
"Use given addresses for block subsidy share paid to the funding stream with id <streamId> (regtest-only)");
|
||||||
}
|
}
|
||||||
string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, "
|
string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, "
|
||||||
"rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these
|
"rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these
|
||||||
|
@ -1036,12 +1039,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
|
|
||||||
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
|
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
|
||||||
|
|
||||||
|
KeyIO keyIO(chainparams);
|
||||||
#ifdef ENABLE_MINING
|
#ifdef ENABLE_MINING
|
||||||
if (mapArgs.count("-mineraddress")) {
|
if (mapArgs.count("-mineraddress")) {
|
||||||
CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]);
|
CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]);
|
||||||
if (!IsValidDestination(addr)) {
|
if (!IsValidDestination(addr)) {
|
||||||
// Try a Sapling address
|
// Try a Sapling address
|
||||||
auto zaddr = DecodePaymentAddress(mapArgs["-mineraddress"]);
|
auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
|
||||||
if (!IsValidPaymentAddress(zaddr) ||
|
if (!IsValidPaymentAddress(zaddr) ||
|
||||||
boost::get<libzcash::SaplingPaymentAddress>(&zaddr) == nullptr)
|
boost::get<libzcash::SaplingPaymentAddress>(&zaddr) == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -1092,6 +1096,45 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mapMultiArgs["-fundingstream"].empty()) {
|
||||||
|
// Allow overriding network upgrade parameters for testing
|
||||||
|
if (Params().NetworkIDString() != "regtest") {
|
||||||
|
return InitError("Funding stream parameters may only be overridden on regtest.");
|
||||||
|
}
|
||||||
|
const std::vector<std::string>& streams = mapMultiArgs["-fundingstream"];
|
||||||
|
for (auto i : streams) {
|
||||||
|
std::vector<std::string> vStreamParams;
|
||||||
|
boost::split(vStreamParams, i, boost::is_any_of(":"));
|
||||||
|
if (vStreamParams.size() != 4) {
|
||||||
|
return InitError("Funding stream parameters malformed, expecting streamId:startHeight:endHeight:comma_delimited_addresses");
|
||||||
|
}
|
||||||
|
int nFundingStreamId;
|
||||||
|
if (!ParseInt32(vStreamParams[0], &nFundingStreamId) ||
|
||||||
|
nFundingStreamId < Consensus::FIRST_FUNDING_STREAM ||
|
||||||
|
nFundingStreamId >= Consensus::MAX_FUNDING_STREAMS) {
|
||||||
|
return InitError(strprintf("Invalid streamId (%s)", vStreamParams[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
int nStartHeight;
|
||||||
|
if (!ParseInt32(vStreamParams[1], &nStartHeight)) {
|
||||||
|
return InitError(strprintf("Invalid funding stream start height (%s)", vStreamParams[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
int nEndHeight;
|
||||||
|
if (!ParseInt32(vStreamParams[2], &nEndHeight)) {
|
||||||
|
return InitError(strprintf("Invalid funding stream end height (%s)", vStreamParams[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> vStreamAddrs;
|
||||||
|
boost::split(vStreamAddrs, vStreamParams[3], boost::is_any_of(","));
|
||||||
|
|
||||||
|
auto fs = Consensus::FundingStream::ParseFundingStream(
|
||||||
|
Params().GetConsensus(), Params(), nStartHeight, nEndHeight, vStreamAddrs);
|
||||||
|
|
||||||
|
UpdateFundingStreamParameters((Consensus::FundingStreamIndex) nFundingStreamId, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
|
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
|
||||||
|
|
||||||
// Initialize libsodium
|
// Initialize libsodium
|
||||||
|
@ -1545,12 +1588,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
bool minerAddressInLocalWallet = false;
|
bool minerAddressInLocalWallet = false;
|
||||||
if (pwalletMain) {
|
if (pwalletMain) {
|
||||||
CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]);
|
CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]);
|
||||||
if (IsValidDestination(addr)) {
|
if (IsValidDestination(addr)) {
|
||||||
CKeyID keyID = boost::get<CKeyID>(addr);
|
CKeyID keyID = boost::get<CKeyID>(addr);
|
||||||
minerAddressInLocalWallet = pwalletMain->HaveKey(keyID);
|
minerAddressInLocalWallet = pwalletMain->HaveKey(keyID);
|
||||||
} else {
|
} else {
|
||||||
auto zaddr = DecodePaymentAddress(mapArgs["-mineraddress"]);
|
auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]);
|
||||||
minerAddressInLocalWallet = boost::apply_visitor(
|
minerAddressInLocalWallet = boost::apply_visitor(
|
||||||
HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
// 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_KEY_CONSTANTS_H
|
||||||
|
#define ZCASH_KEY_CONSTANTS_H
|
||||||
|
|
||||||
|
class KeyConstants
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Base58Type {
|
||||||
|
PUBKEY_ADDRESS,
|
||||||
|
SCRIPT_ADDRESS,
|
||||||
|
SECRET_KEY,
|
||||||
|
EXT_PUBLIC_KEY,
|
||||||
|
EXT_SECRET_KEY,
|
||||||
|
|
||||||
|
ZCPAYMENT_ADDRESS,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual const std::vector<unsigned char>& Base58Prefix(Base58Type type) const =0;
|
||||||
|
virtual const std::string& Bech32HRP(Bech32Type type) const =0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ZCASH_KEY_CONSTANTS_H
|
166
src/key_io.cpp
166
src/key_io.cpp
|
@ -22,21 +22,21 @@ namespace
|
||||||
class DestinationEncoder : public boost::static_visitor<std::string>
|
class DestinationEncoder : public boost::static_visitor<std::string>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const CChainParams& m_params;
|
const KeyConstants& keyConstants;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DestinationEncoder(const CChainParams& params) : m_params(params) {}
|
DestinationEncoder(const KeyConstants& keyConstants) : keyConstants(keyConstants) {}
|
||||||
|
|
||||||
std::string operator()(const CKeyID& id) const
|
std::string operator()(const CKeyID& id) const
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::PUBKEY_ADDRESS);
|
||||||
data.insert(data.end(), id.begin(), id.end());
|
data.insert(data.end(), id.begin(), id.end());
|
||||||
return EncodeBase58Check(data);
|
return EncodeBase58Check(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator()(const CScriptID& id) const
|
std::string operator()(const CScriptID& id) const
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::SCRIPT_ADDRESS);
|
||||||
data.insert(data.end(), id.begin(), id.end());
|
data.insert(data.end(), id.begin(), id.end());
|
||||||
return EncodeBase58Check(data);
|
return EncodeBase58Check(data);
|
||||||
}
|
}
|
||||||
|
@ -44,43 +44,19 @@ public:
|
||||||
std::string operator()(const CNoDestination& no) const { return {}; }
|
std::string operator()(const CNoDestination& no) const { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
|
|
||||||
{
|
|
||||||
std::vector<unsigned char> data;
|
|
||||||
uint160 hash;
|
|
||||||
if (DecodeBase58Check(str, data)) {
|
|
||||||
// base58-encoded Bitcoin addresses.
|
|
||||||
// Public-key-hash-addresses have version 0 (or 111 testnet).
|
|
||||||
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
|
||||||
const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
|
|
||||||
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
|
|
||||||
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
|
|
||||||
return CKeyID(hash);
|
|
||||||
}
|
|
||||||
// Script-hash-addresses have version 5 (or 196 testnet).
|
|
||||||
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
|
|
||||||
const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
|
|
||||||
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
|
|
||||||
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
|
|
||||||
return CScriptID(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CNoDestination();
|
|
||||||
}
|
|
||||||
|
|
||||||
class PaymentAddressEncoder : public boost::static_visitor<std::string>
|
class PaymentAddressEncoder : public boost::static_visitor<std::string>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const CChainParams& m_params;
|
const KeyConstants& keyConstants;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
|
PaymentAddressEncoder(const KeyConstants& keyConstants) : keyConstants(keyConstants) {}
|
||||||
|
|
||||||
std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
|
std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
|
||||||
{
|
{
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << zaddr;
|
ss << zaddr;
|
||||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::ZCPAYMENT_ADDRESS);
|
||||||
data.insert(data.end(), ss.begin(), ss.end());
|
data.insert(data.end(), ss.begin(), ss.end());
|
||||||
return EncodeBase58Check(data);
|
return EncodeBase58Check(data);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +71,7 @@ public:
|
||||||
// See calculation comment below
|
// See calculation comment below
|
||||||
data.reserve((seraddr.size() * 8 + 4) / 5);
|
data.reserve((seraddr.size() * 8 + 4) / 5);
|
||||||
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
|
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
|
||||||
return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data);
|
return bech32::Encode(keyConstants.Bech32HRP(KeyConstants::SAPLING_PAYMENT_ADDRESS), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
|
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
|
||||||
|
@ -104,16 +80,16 @@ public:
|
||||||
class ViewingKeyEncoder : public boost::static_visitor<std::string>
|
class ViewingKeyEncoder : public boost::static_visitor<std::string>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const CChainParams& m_params;
|
const KeyConstants& keyConstants;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
|
ViewingKeyEncoder(const KeyConstants& keyConstants) : keyConstants(keyConstants) {}
|
||||||
|
|
||||||
std::string operator()(const libzcash::SproutViewingKey& vk) const
|
std::string operator()(const libzcash::SproutViewingKey& vk) const
|
||||||
{
|
{
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << vk;
|
ss << vk;
|
||||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::ZCVIEWING_KEY);
|
||||||
data.insert(data.end(), ss.begin(), ss.end());
|
data.insert(data.end(), ss.begin(), ss.end());
|
||||||
std::string ret = EncodeBase58Check(data);
|
std::string ret = EncodeBase58Check(data);
|
||||||
memory_cleanse(data.data(), data.size());
|
memory_cleanse(data.data(), data.size());
|
||||||
|
@ -130,7 +106,7 @@ public:
|
||||||
// See calculation comment below
|
// See calculation comment below
|
||||||
data.reserve((serkey.size() * 8 + 4) / 5);
|
data.reserve((serkey.size() * 8 + 4) / 5);
|
||||||
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
|
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
|
||||||
std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK), data);
|
std::string ret = bech32::Encode(keyConstants.Bech32HRP(KeyConstants::SAPLING_EXTENDED_FVK), data);
|
||||||
memory_cleanse(serkey.data(), serkey.size());
|
memory_cleanse(serkey.data(), serkey.size());
|
||||||
memory_cleanse(data.data(), data.size());
|
memory_cleanse(data.data(), data.size());
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -142,16 +118,16 @@ public:
|
||||||
class SpendingKeyEncoder : public boost::static_visitor<std::string>
|
class SpendingKeyEncoder : public boost::static_visitor<std::string>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const CChainParams& m_params;
|
const KeyConstants& keyConstants;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
|
SpendingKeyEncoder(const KeyConstants& keyConstants) : keyConstants(keyConstants) {}
|
||||||
|
|
||||||
std::string operator()(const libzcash::SproutSpendingKey& zkey) const
|
std::string operator()(const libzcash::SproutSpendingKey& zkey) const
|
||||||
{
|
{
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << zkey;
|
ss << zkey;
|
||||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::ZCSPENDING_KEY);
|
||||||
data.insert(data.end(), ss.begin(), ss.end());
|
data.insert(data.end(), ss.begin(), ss.end());
|
||||||
std::string ret = EncodeBase58Check(data);
|
std::string ret = EncodeBase58Check(data);
|
||||||
memory_cleanse(data.data(), data.size());
|
memory_cleanse(data.data(), data.size());
|
||||||
|
@ -168,7 +144,7 @@ public:
|
||||||
// See calculation comment below
|
// See calculation comment below
|
||||||
data.reserve((serkey.size() * 8 + 4) / 5);
|
data.reserve((serkey.size() * 8 + 4) / 5);
|
||||||
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
|
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
|
||||||
std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data);
|
std::string ret = bech32::Encode(keyConstants.Bech32HRP(KeyConstants::SAPLING_EXTENDED_SPEND_KEY), data);
|
||||||
memory_cleanse(serkey.data(), serkey.size());
|
memory_cleanse(serkey.data(), serkey.size());
|
||||||
memory_cleanse(data.data(), data.size());
|
memory_cleanse(data.data(), data.size());
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -186,12 +162,36 @@ const size_t ConvertedSaplingExtendedFullViewingKeySize = (ZIP32_XFVK_SIZE * 8 +
|
||||||
const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5;
|
const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CKey DecodeSecret(const std::string& str)
|
CTxDestination KeyIO::DecodeDestination(const std::string& str)
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> data;
|
||||||
|
uint160 hash;
|
||||||
|
if (DecodeBase58Check(str, data)) {
|
||||||
|
// base58-encoded Bitcoin addresses.
|
||||||
|
// Public-key-hash-addresses have version 0 (or 111 testnet).
|
||||||
|
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
||||||
|
const std::vector<unsigned char>& pubkey_prefix = keyConstants.Base58Prefix(KeyConstants::PUBKEY_ADDRESS);
|
||||||
|
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
|
||||||
|
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
|
||||||
|
return CKeyID(hash);
|
||||||
|
}
|
||||||
|
// Script-hash-addresses have version 5 (or 196 testnet).
|
||||||
|
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
|
||||||
|
const std::vector<unsigned char>& script_prefix = keyConstants.Base58Prefix(KeyConstants::SCRIPT_ADDRESS);
|
||||||
|
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
|
||||||
|
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
|
||||||
|
return CScriptID(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CNoDestination();
|
||||||
|
};
|
||||||
|
|
||||||
|
CKey KeyIO::DecodeSecret(const std::string& str)
|
||||||
{
|
{
|
||||||
CKey key;
|
CKey key;
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
if (DecodeBase58Check(str, data)) {
|
if (DecodeBase58Check(str, data)) {
|
||||||
const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
|
const std::vector<unsigned char>& privkey_prefix = keyConstants.Base58Prefix(KeyConstants::SECRET_KEY);
|
||||||
if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
|
if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
|
||||||
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
|
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
|
||||||
bool compressed = data.size() == 33 + privkey_prefix.size();
|
bool compressed = data.size() == 33 + privkey_prefix.size();
|
||||||
|
@ -202,10 +202,10 @@ CKey DecodeSecret(const std::string& str)
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EncodeSecret(const CKey& key)
|
std::string KeyIO::EncodeSecret(const CKey& key)
|
||||||
{
|
{
|
||||||
assert(key.IsValid());
|
assert(key.IsValid());
|
||||||
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::SECRET_KEY);
|
||||||
data.insert(data.end(), key.begin(), key.end());
|
data.insert(data.end(), key.begin(), key.end());
|
||||||
if (key.IsCompressed()) {
|
if (key.IsCompressed()) {
|
||||||
data.push_back(1);
|
data.push_back(1);
|
||||||
|
@ -215,12 +215,12 @@ std::string EncodeSecret(const CKey& key)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CExtPubKey DecodeExtPubKey(const std::string& str)
|
CExtPubKey KeyIO::DecodeExtPubKey(const std::string& str)
|
||||||
{
|
{
|
||||||
CExtPubKey key;
|
CExtPubKey key;
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
if (DecodeBase58Check(str, data)) {
|
if (DecodeBase58Check(str, data)) {
|
||||||
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
|
const std::vector<unsigned char>& prefix = keyConstants.Base58Prefix(KeyConstants::EXT_PUBLIC_KEY);
|
||||||
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
||||||
key.Decode(data.data() + prefix.size());
|
key.Decode(data.data() + prefix.size());
|
||||||
}
|
}
|
||||||
|
@ -228,9 +228,9 @@ CExtPubKey DecodeExtPubKey(const std::string& str)
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EncodeExtPubKey(const CExtPubKey& key)
|
std::string KeyIO::EncodeExtPubKey(const CExtPubKey& key)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::EXT_PUBLIC_KEY);
|
||||||
size_t size = data.size();
|
size_t size = data.size();
|
||||||
data.resize(size + BIP32_EXTKEY_SIZE);
|
data.resize(size + BIP32_EXTKEY_SIZE);
|
||||||
key.Encode(data.data() + size);
|
key.Encode(data.data() + size);
|
||||||
|
@ -238,12 +238,12 @@ std::string EncodeExtPubKey(const CExtPubKey& key)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CExtKey DecodeExtKey(const std::string& str)
|
CExtKey KeyIO::DecodeExtKey(const std::string& str)
|
||||||
{
|
{
|
||||||
CExtKey key;
|
CExtKey key;
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
if (DecodeBase58Check(str, data)) {
|
if (DecodeBase58Check(str, data)) {
|
||||||
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
|
const std::vector<unsigned char>& prefix = keyConstants.Base58Prefix(KeyConstants::EXT_SECRET_KEY);
|
||||||
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
||||||
key.Decode(data.data() + prefix.size());
|
key.Decode(data.data() + prefix.size());
|
||||||
}
|
}
|
||||||
|
@ -251,9 +251,9 @@ CExtKey DecodeExtKey(const std::string& str)
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EncodeExtKey(const CExtKey& key)
|
std::string KeyIO::EncodeExtKey(const CExtKey& key)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
|
std::vector<unsigned char> data = keyConstants.Base58Prefix(KeyConstants::EXT_SECRET_KEY);
|
||||||
size_t size = data.size();
|
size_t size = data.size();
|
||||||
data.resize(size + BIP32_EXTKEY_SIZE);
|
data.resize(size + BIP32_EXTKEY_SIZE);
|
||||||
key.Encode(data.data() + size);
|
key.Encode(data.data() + size);
|
||||||
|
@ -262,40 +262,31 @@ std::string EncodeExtKey(const CExtKey& key)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EncodeDestination(const CTxDestination& dest)
|
std::string KeyIO::EncodeDestination(const CTxDestination& dest)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(DestinationEncoder(Params()), dest);
|
return boost::apply_visitor(DestinationEncoder(keyConstants), dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination DecodeDestination(const std::string& str)
|
bool KeyIO::IsValidDestinationString(const std::string& str)
|
||||||
{
|
{
|
||||||
return DecodeDestination(str, Params());
|
return IsValidDestination(DecodeDestination(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
|
std::string KeyIO::EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
|
||||||
{
|
{
|
||||||
return IsValidDestination(DecodeDestination(str, params));
|
return boost::apply_visitor(PaymentAddressEncoder(keyConstants), zaddr);
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValidDestinationString(const std::string& str)
|
|
||||||
{
|
|
||||||
return IsValidDestinationString(str, Params());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
|
|
||||||
{
|
|
||||||
return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T1, typename T2, typename T3>
|
template<typename T1, typename T2, typename T3>
|
||||||
T1 DecodeAny(
|
T1 DecodeAny(
|
||||||
|
const KeyConstants& keyConstants,
|
||||||
const std::string& str,
|
const std::string& str,
|
||||||
std::pair<CChainParams::Base58Type, size_t> sprout,
|
std::pair<KeyConstants::Base58Type, size_t> sprout,
|
||||||
std::pair<CChainParams::Bech32Type, size_t> sapling)
|
std::pair<KeyConstants::Bech32Type, size_t> sapling)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
if (DecodeBase58Check(str, data)) {
|
if (DecodeBase58Check(str, data)) {
|
||||||
const std::vector<unsigned char>& prefix = Params().Base58Prefix(sprout.first);
|
const std::vector<unsigned char>& prefix = keyConstants.Base58Prefix(sprout.first);
|
||||||
if ((data.size() == sprout.second + prefix.size()) &&
|
if ((data.size() == sprout.second + prefix.size()) &&
|
||||||
std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
std::equal(prefix.begin(), prefix.end(), data.begin())) {
|
||||||
CSerializeData serialized(data.begin() + prefix.size(), data.end());
|
CSerializeData serialized(data.begin() + prefix.size(), data.end());
|
||||||
|
@ -310,7 +301,7 @@ T1 DecodeAny(
|
||||||
|
|
||||||
data.clear();
|
data.clear();
|
||||||
auto bech = bech32::Decode(str);
|
auto bech = bech32::Decode(str);
|
||||||
if (bech.first == Params().Bech32HRP(sapling.first) &&
|
if (bech.first == keyConstants.Bech32HRP(sapling.first) &&
|
||||||
bech.second.size() == sapling.second) {
|
bech.second.size() == sapling.second) {
|
||||||
// Bech32 decoding
|
// Bech32 decoding
|
||||||
data.reserve((bech.second.size() * 5) / 8);
|
data.reserve((bech.second.size() * 5) / 8);
|
||||||
|
@ -327,50 +318,53 @@ T1 DecodeAny(
|
||||||
return libzcash::InvalidEncoding();
|
return libzcash::InvalidEncoding();
|
||||||
}
|
}
|
||||||
|
|
||||||
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
|
libzcash::PaymentAddress KeyIO::DecodePaymentAddress(const std::string& str)
|
||||||
{
|
{
|
||||||
return DecodeAny<libzcash::PaymentAddress,
|
return DecodeAny<libzcash::PaymentAddress,
|
||||||
libzcash::SproutPaymentAddress,
|
libzcash::SproutPaymentAddress,
|
||||||
libzcash::SaplingPaymentAddress>(
|
libzcash::SaplingPaymentAddress>(
|
||||||
|
keyConstants,
|
||||||
str,
|
str,
|
||||||
std::make_pair(CChainParams::ZCPAYMENT_ADDRRESS, libzcash::SerializedSproutPaymentAddressSize),
|
std::make_pair(KeyConstants::ZCPAYMENT_ADDRESS, libzcash::SerializedSproutPaymentAddressSize),
|
||||||
std::make_pair(CChainParams::SAPLING_PAYMENT_ADDRESS, ConvertedSaplingPaymentAddressSize)
|
std::make_pair(KeyConstants::SAPLING_PAYMENT_ADDRESS, ConvertedSaplingPaymentAddressSize)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidPaymentAddressString(const std::string& str) {
|
bool KeyIO::IsValidPaymentAddressString(const std::string& str) {
|
||||||
return IsValidPaymentAddress(DecodePaymentAddress(str));
|
return IsValidPaymentAddress(DecodePaymentAddress(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
|
std::string KeyIO::EncodeViewingKey(const libzcash::ViewingKey& vk)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
|
return boost::apply_visitor(ViewingKeyEncoder(keyConstants), vk);
|
||||||
}
|
}
|
||||||
|
|
||||||
libzcash::ViewingKey DecodeViewingKey(const std::string& str)
|
libzcash::ViewingKey KeyIO::DecodeViewingKey(const std::string& str)
|
||||||
{
|
{
|
||||||
return DecodeAny<libzcash::ViewingKey,
|
return DecodeAny<libzcash::ViewingKey,
|
||||||
libzcash::SproutViewingKey,
|
libzcash::SproutViewingKey,
|
||||||
libzcash::SaplingExtendedFullViewingKey>(
|
libzcash::SaplingExtendedFullViewingKey>(
|
||||||
|
keyConstants,
|
||||||
str,
|
str,
|
||||||
std::make_pair(CChainParams::ZCVIEWING_KEY, libzcash::SerializedSproutViewingKeySize),
|
std::make_pair(KeyConstants::ZCVIEWING_KEY, libzcash::SerializedSproutViewingKeySize),
|
||||||
std::make_pair(CChainParams::SAPLING_EXTENDED_FVK, ConvertedSaplingExtendedFullViewingKeySize)
|
std::make_pair(KeyConstants::SAPLING_EXTENDED_FVK, ConvertedSaplingExtendedFullViewingKeySize)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
|
std::string KeyIO::EncodeSpendingKey(const libzcash::SpendingKey& zkey)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
|
return boost::apply_visitor(SpendingKeyEncoder(keyConstants), zkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
|
libzcash::SpendingKey KeyIO::DecodeSpendingKey(const std::string& str)
|
||||||
{
|
{
|
||||||
|
|
||||||
return DecodeAny<libzcash::SpendingKey,
|
return DecodeAny<libzcash::SpendingKey,
|
||||||
libzcash::SproutSpendingKey,
|
libzcash::SproutSpendingKey,
|
||||||
libzcash::SaplingExtendedSpendingKey>(
|
libzcash::SaplingExtendedSpendingKey>(
|
||||||
|
keyConstants,
|
||||||
str,
|
str,
|
||||||
std::make_pair(CChainParams::ZCSPENDING_KEY, libzcash::SerializedSproutSpendingKeySize),
|
std::make_pair(KeyConstants::ZCSPENDING_KEY, libzcash::SerializedSproutSpendingKeySize),
|
||||||
std::make_pair(CChainParams::SAPLING_EXTENDED_SPEND_KEY, ConvertedSaplingExtendedSpendingKeySize)
|
std::make_pair(KeyConstants::SAPLING_EXTENDED_SPEND_KEY, ConvertedSaplingExtendedSpendingKeySize)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
11
src/key_io.h
11
src/key_io.h
|
@ -13,8 +13,16 @@
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
#include <zcash/Address.hpp>
|
#include <zcash/Address.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
class KeyIO {
|
||||||
|
private:
|
||||||
|
const KeyConstants& keyConstants;
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeyIO(const KeyConstants& keyConstants): keyConstants(keyConstants) { }
|
||||||
|
|
||||||
CKey DecodeSecret(const std::string& str);
|
CKey DecodeSecret(const std::string& str);
|
||||||
std::string EncodeSecret(const CKey& key);
|
std::string EncodeSecret(const CKey& key);
|
||||||
|
|
||||||
|
@ -25,8 +33,8 @@ std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
|
||||||
|
|
||||||
std::string EncodeDestination(const CTxDestination& dest);
|
std::string EncodeDestination(const CTxDestination& dest);
|
||||||
CTxDestination DecodeDestination(const std::string& str);
|
CTxDestination DecodeDestination(const std::string& str);
|
||||||
|
|
||||||
bool IsValidDestinationString(const std::string& str);
|
bool IsValidDestinationString(const std::string& str);
|
||||||
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
|
|
||||||
|
|
||||||
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
|
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
|
||||||
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str);
|
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str);
|
||||||
|
@ -37,5 +45,6 @@ libzcash::ViewingKey DecodeViewingKey(const std::string& str);
|
||||||
|
|
||||||
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey);
|
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey);
|
||||||
libzcash::SpendingKey DecodeSpendingKey(const std::string& str);
|
libzcash::SpendingKey DecodeSpendingKey(const std::string& str);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_KEYIO_H
|
#endif // BITCOIN_KEYIO_H
|
||||||
|
|
55
src/main.cpp
55
src/main.cpp
|
@ -15,11 +15,13 @@
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
#include "checkqueue.h"
|
#include "checkqueue.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/funding.h"
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "deprecation.h"
|
#include "deprecation.h"
|
||||||
#include "experimental_features.h"
|
#include "experimental_features.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
|
#include "key_io.h"
|
||||||
#include "merkleblock.h"
|
#include "merkleblock.h"
|
||||||
#include "metrics.h"
|
#include "metrics.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
@ -901,6 +903,18 @@ bool ContextualCheckTransaction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From Canopy onward, coinbase transaction must include outputs corresponding to the
|
||||||
|
// ZIP 207 consensus funding streams active at the current block height. To avoid
|
||||||
|
// double-decrypting, we detect any shielded funding streams during the Heartwood
|
||||||
|
// consensus check. If Canopy is not yet active, fundingStreamElements will be empty.
|
||||||
|
std::set<Consensus::FundingStreamElement> fundingStreamElements;
|
||||||
|
if (canopyActive) {
|
||||||
|
fundingStreamElements = Consensus::GetActiveFundingStreamElements(
|
||||||
|
nHeight,
|
||||||
|
GetBlockSubsidy(nHeight, chainparams.GetConsensus()),
|
||||||
|
chainparams.GetConsensus());
|
||||||
|
}
|
||||||
|
|
||||||
// Rules that apply to Heartwood or later:
|
// Rules that apply to Heartwood or later:
|
||||||
if (heartwoodActive) {
|
if (heartwoodActive) {
|
||||||
if (tx.IsCoinBase()) {
|
if (tx.IsCoinBase()) {
|
||||||
|
@ -920,7 +934,6 @@ bool ContextualCheckTransaction(
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaplingNotePlaintext::decrypt() checks note commitment validity.
|
// SaplingNotePlaintext::decrypt() checks note commitment validity.
|
||||||
|
|
||||||
auto encPlaintext = SaplingNotePlaintext::decrypt(
|
auto encPlaintext = SaplingNotePlaintext::decrypt(
|
||||||
chainparams.GetConsensus(),
|
chainparams.GetConsensus(),
|
||||||
nHeight,
|
nHeight,
|
||||||
|
@ -929,6 +942,7 @@ bool ContextualCheckTransaction(
|
||||||
outPlaintext->esk,
|
outPlaintext->esk,
|
||||||
outPlaintext->pk_d,
|
outPlaintext->pk_d,
|
||||||
output.cmu);
|
output.cmu);
|
||||||
|
|
||||||
if (!encPlaintext) {
|
if (!encPlaintext) {
|
||||||
return state.DoS(
|
return state.DoS(
|
||||||
DOS_LEVEL_BLOCK,
|
DOS_LEVEL_BLOCK,
|
||||||
|
@ -937,6 +951,18 @@ bool ContextualCheckTransaction(
|
||||||
"bad-cb-output-desc-invalid-encct");
|
"bad-cb-output-desc-invalid-encct");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ZIP 207: detect shielded funding stream elements
|
||||||
|
if (canopyActive) {
|
||||||
|
libzcash::SaplingPaymentAddress zaddr(encPlaintext->d, outPlaintext->pk_d);
|
||||||
|
for (auto it = fundingStreamElements.begin(); it != fundingStreamElements.end(); ++it) {
|
||||||
|
const libzcash::SaplingPaymentAddress* streamAddr = boost::get<libzcash::SaplingPaymentAddress>(&(it->first));
|
||||||
|
if (streamAddr && zaddr == *streamAddr && encPlaintext->value() == it->second) {
|
||||||
|
fundingStreamElements.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ZIP 212: Check that the note plaintexts use the v2 note plaintext
|
// ZIP 212: Check that the note plaintexts use the v2 note plaintext
|
||||||
// version.
|
// version.
|
||||||
// This check compels miners to switch to the new plaintext version
|
// This check compels miners to switch to the new plaintext version
|
||||||
|
@ -959,6 +985,25 @@ bool ContextualCheckTransaction(
|
||||||
return state.DoS(DOS_LEVEL_BLOCK, error("ContextualCheckTransaction(): joinsplit.vpub_old nonzero"), REJECT_INVALID, "bad-txns-vpub_old-nonzero");
|
return state.DoS(DOS_LEVEL_BLOCK, error("ContextualCheckTransaction(): joinsplit.vpub_old nonzero"), REJECT_INVALID, "bad-txns-vpub_old-nonzero");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tx.IsCoinBase()) {
|
||||||
|
// Detect transparent funding streams.
|
||||||
|
for (const CTxOut& output : tx.vout) {
|
||||||
|
for (auto it = fundingStreamElements.begin(); it != fundingStreamElements.end(); ++it) {
|
||||||
|
const CScript* taddr = boost::get<CScript>(&(it->first));
|
||||||
|
if (taddr && output.scriptPubKey == *taddr && output.nValue == it->second) {
|
||||||
|
fundingStreamElements.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fundingStreamElements.empty()) {
|
||||||
|
std::cout << "\nFunding stream missing at height " << nHeight;
|
||||||
|
return state.DoS(100, error("%s: funding stream missing", __func__),
|
||||||
|
REJECT_INVALID, "cb-funding-stream-missing");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
|
auto consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
|
||||||
|
@ -1821,7 +1866,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
|
||||||
// Mining slow start
|
// Mining slow start
|
||||||
// The subsidy is ramped up linearly, skipping the middle payout of
|
// The subsidy is ramped up linearly, skipping the middle payout of
|
||||||
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
|
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
|
||||||
if (nHeight < consensusParams.nSubsidySlowStartInterval / 2) {
|
if (nHeight < consensusParams.SubsidySlowStartShift()) {
|
||||||
nSubsidy /= consensusParams.nSubsidySlowStartInterval;
|
nSubsidy /= consensusParams.nSubsidySlowStartInterval;
|
||||||
nSubsidy *= nHeight;
|
nSubsidy *= nHeight;
|
||||||
return nSubsidy;
|
return nSubsidy;
|
||||||
|
@ -1831,7 +1876,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
|
||||||
return nSubsidy;
|
return nSubsidy;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(nHeight > consensusParams.SubsidySlowStartShift());
|
assert(nHeight >= consensusParams.SubsidySlowStartShift());
|
||||||
|
|
||||||
int halvings = consensusParams.Halving(nHeight);
|
int halvings = consensusParams.Halving(nHeight);
|
||||||
|
|
||||||
|
@ -4132,12 +4177,14 @@ bool ContextualCheckBlock(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY)) {
|
||||||
|
// Funding streams are checked inside ContextualCheckTransaction.
|
||||||
|
} else if ((nHeight > 0) && (nHeight <= consensusParams.GetLastFoundersRewardBlockHeight(nHeight))) {
|
||||||
// Coinbase transaction must include an output sending 20% of
|
// Coinbase transaction must include an output sending 20% of
|
||||||
// the block subsidy to a Founders' Reward script, until the last Founders'
|
// the block subsidy to a Founders' Reward script, until the last Founders'
|
||||||
// Reward block is reached, with exception of the genesis block.
|
// Reward block is reached, with exception of the genesis block.
|
||||||
// The last Founders' Reward block is defined as the block just before the
|
// The last Founders' Reward block is defined as the block just before the
|
||||||
// first subsidy halving block, which occurs at halving_interval + slow_start_shift.
|
// first subsidy halving block, which occurs at halving_interval + slow_start_shift.
|
||||||
if ((nHeight > 0) && (nHeight <= consensusParams.GetLastFoundersRewardBlockHeight(nHeight))) {
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxOut& output, block.vtx[0].vout) {
|
BOOST_FOREACH(const CTxOut& output, block.vtx[0].vout) {
|
||||||
|
|
|
@ -465,7 +465,10 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state,
|
||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins,
|
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins,
|
||||||
const CChainParams& chainparams, bool fJustCheck = false);
|
const CChainParams& chainparams, bool fJustCheck = false);
|
||||||
|
|
||||||
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
|
/**
|
||||||
|
* Check a block is completely valid from start to finish (only works on top
|
||||||
|
* of our current best block, with cs_main held)
|
||||||
|
*/
|
||||||
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
|
|
||||||
|
|
161
src/miner.cpp
161
src/miner.cpp
|
@ -11,6 +11,7 @@
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/funding.h"
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#ifdef ENABLE_MINING
|
#ifdef ENABLE_MINING
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "metrics.h"
|
#include "metrics.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "zcash/Note.hpp"
|
||||||
#include "policy/policy.h"
|
#include "policy/policy.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
@ -119,6 +121,42 @@ bool IsValidMinerAddress(const MinerAddress& minerAddr) {
|
||||||
return minerAddr.which() != 0;
|
return minerAddr.which() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddFundingStreamValueToTx : public boost::static_visitor<bool>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CMutableTransaction &mtx;
|
||||||
|
void* ctx;
|
||||||
|
const CAmount fundingStreamValue;
|
||||||
|
const libzcash::Zip212Enabled zip212Enabled;
|
||||||
|
public:
|
||||||
|
AddFundingStreamValueToTx(
|
||||||
|
CMutableTransaction &mtx,
|
||||||
|
void* ctx,
|
||||||
|
const CAmount fundingStreamValue,
|
||||||
|
const libzcash::Zip212Enabled zip212Enabled): mtx(mtx), ctx(ctx), fundingStreamValue(fundingStreamValue), zip212Enabled(zip212Enabled) {}
|
||||||
|
|
||||||
|
bool operator()(const libzcash::SaplingPaymentAddress& pa) const {
|
||||||
|
uint256 ovk;
|
||||||
|
auto note = libzcash::SaplingNote(pa, fundingStreamValue, zip212Enabled);
|
||||||
|
auto output = OutputDescriptionInfo(ovk, note, NO_MEMO);
|
||||||
|
|
||||||
|
auto odesc = output.Build(ctx);
|
||||||
|
if (odesc) {
|
||||||
|
mtx.vShieldedOutput.push_back(odesc.get());
|
||||||
|
mtx.valueBalance -= fundingStreamValue;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const CScript& scriptPubKey) const {
|
||||||
|
mtx.vout.push_back(CTxOut(fundingStreamValue, scriptPubKey));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class AddOutputsToCoinbaseTxAndSign : public boost::static_visitor<>
|
class AddOutputsToCoinbaseTxAndSign : public boost::static_visitor<>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -134,45 +172,50 @@ public:
|
||||||
const int nHeight,
|
const int nHeight,
|
||||||
const CAmount nFees) : mtx(mtx), chainparams(chainparams), nHeight(nHeight), nFees(nFees) {}
|
const CAmount nFees) : mtx(mtx), chainparams(chainparams), nHeight(nHeight), nFees(nFees) {}
|
||||||
|
|
||||||
CAmount SetFoundersRewardAndGetMinerValue() const {
|
const libzcash::Zip212Enabled GetZip212Flag() const {
|
||||||
auto value = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY)) {
|
||||||
|
return libzcash::Zip212Enabled::AfterZip212;
|
||||||
|
} else {
|
||||||
|
return libzcash::Zip212Enabled::BeforeZip212;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((nHeight > 0) && (nHeight <= chainparams.GetConsensus().GetLastFoundersRewardBlockHeight(nHeight))) {
|
CAmount SetFoundersRewardAndGetMinerValue(void* ctx) const {
|
||||||
|
auto block_subsidy = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
||||||
|
auto miner_reward = block_subsidy; // founders' reward or funding stream amounts will be subtracted below
|
||||||
|
|
||||||
|
if (nHeight > 0) {
|
||||||
|
if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY)) {
|
||||||
|
auto fundingStreamElements = Consensus::GetActiveFundingStreamElements(
|
||||||
|
nHeight,
|
||||||
|
block_subsidy,
|
||||||
|
chainparams.GetConsensus());
|
||||||
|
|
||||||
|
for (Consensus::FundingStreamElement fselem : fundingStreamElements) {
|
||||||
|
miner_reward -= fselem.second;
|
||||||
|
bool added = boost::apply_visitor(AddFundingStreamValueToTx(mtx, ctx, fselem.second, GetZip212Flag()), fselem.first);
|
||||||
|
if (!added) {
|
||||||
|
librustzcash_sapling_proving_ctx_free(ctx);
|
||||||
|
throw new std::runtime_error("Failed to add funding stream output.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (nHeight <= chainparams.GetConsensus().GetLastFoundersRewardBlockHeight(nHeight)) {
|
||||||
// Founders reward is 20% of the block subsidy
|
// Founders reward is 20% of the block subsidy
|
||||||
auto vFoundersReward = value / 5;
|
auto vFoundersReward = miner_reward / 5;
|
||||||
// Take some reward away from us
|
// Take some reward away from us
|
||||||
value -= vFoundersReward;
|
miner_reward -= vFoundersReward;
|
||||||
// And give it to the founders
|
// And give it to the founders
|
||||||
mtx.vout.push_back(CTxOut(vFoundersReward, chainparams.GetFoundersRewardScriptAtHeight(nHeight)));
|
mtx.vout.push_back(CTxOut(vFoundersReward, chainparams.GetFoundersRewardScriptAtHeight(nHeight)));
|
||||||
|
} else {
|
||||||
|
// Founders reward ends without replacement if Canopy is not activated by the
|
||||||
|
// last Founders' Reward block height + 1.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value + nFees;
|
return miner_reward + nFees;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const InvalidMinerAddress &invalid) const {}
|
void ComputeBindingSig(void* ctx) const {
|
||||||
|
|
||||||
// Create shielded output
|
|
||||||
void operator()(const libzcash::SaplingPaymentAddress &pa) const {
|
|
||||||
auto value = SetFoundersRewardAndGetMinerValue();
|
|
||||||
mtx.valueBalance = -value;
|
|
||||||
|
|
||||||
uint256 ovk;
|
|
||||||
libzcash::Zip212Enabled zip_212_enabled = libzcash::Zip212Enabled::BeforeZip212;
|
|
||||||
if (Params().GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY)) {
|
|
||||||
zip_212_enabled = libzcash::Zip212Enabled::AfterZip212;
|
|
||||||
}
|
|
||||||
auto note = libzcash::SaplingNote(pa, value, zip_212_enabled);
|
|
||||||
auto output = OutputDescriptionInfo(ovk, note, {{0xF6}});
|
|
||||||
|
|
||||||
auto ctx = librustzcash_sapling_proving_ctx_init();
|
|
||||||
|
|
||||||
auto odesc = output.Build(ctx);
|
|
||||||
if (!odesc) {
|
|
||||||
librustzcash_sapling_proving_ctx_free(ctx);
|
|
||||||
throw new std::runtime_error("Failed to create shielded output for miner");
|
|
||||||
}
|
|
||||||
mtx.vShieldedOutput.push_back(odesc.get());
|
|
||||||
|
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
uint256 dataToBeSigned;
|
uint256 dataToBeSigned;
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
|
@ -185,24 +228,62 @@ public:
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
librustzcash_sapling_binding_sig(
|
bool success = librustzcash_sapling_binding_sig(
|
||||||
ctx,
|
ctx,
|
||||||
mtx.valueBalance,
|
mtx.valueBalance,
|
||||||
dataToBeSigned.begin(),
|
dataToBeSigned.begin(),
|
||||||
mtx.bindingSig.data());
|
mtx.bindingSig.data());
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
librustzcash_sapling_proving_ctx_free(ctx);
|
||||||
|
throw new std::runtime_error("An error occurred computing the binding signature.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const InvalidMinerAddress &invalid) const {}
|
||||||
|
|
||||||
|
// Create shielded output
|
||||||
|
void operator()(const libzcash::SaplingPaymentAddress &pa) const {
|
||||||
|
auto ctx = librustzcash_sapling_proving_ctx_init();
|
||||||
|
|
||||||
|
auto miner_reward = SetFoundersRewardAndGetMinerValue(ctx);
|
||||||
|
mtx.valueBalance -= miner_reward;
|
||||||
|
|
||||||
|
uint256 ovk;
|
||||||
|
|
||||||
|
auto note = libzcash::SaplingNote(pa, miner_reward, GetZip212Flag());
|
||||||
|
auto output = OutputDescriptionInfo(ovk, note, NO_MEMO);
|
||||||
|
|
||||||
|
auto odesc = output.Build(ctx);
|
||||||
|
if (!odesc) {
|
||||||
|
librustzcash_sapling_proving_ctx_free(ctx);
|
||||||
|
throw new std::runtime_error("Failed to create shielded output for miner");
|
||||||
|
}
|
||||||
|
mtx.vShieldedOutput.push_back(odesc.get());
|
||||||
|
|
||||||
|
ComputeBindingSig(ctx);
|
||||||
|
|
||||||
librustzcash_sapling_proving_ctx_free(ctx);
|
librustzcash_sapling_proving_ctx_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create transparent output
|
// Create transparent output
|
||||||
void operator()(const boost::shared_ptr<CReserveScript> &coinbaseScript) const {
|
void operator()(const boost::shared_ptr<CReserveScript> &coinbaseScript) const {
|
||||||
// Create the miner's output.
|
|
||||||
mtx.vout.resize(1);
|
|
||||||
// Add the FR output and fetch the miner's output value.
|
// Add the FR output and fetch the miner's output value.
|
||||||
auto value = SetFoundersRewardAndGetMinerValue();
|
auto ctx = librustzcash_sapling_proving_ctx_init();
|
||||||
|
|
||||||
|
// Miner output will be vout[0]; Founders' Reward & funding stream outputs
|
||||||
|
// will follow.
|
||||||
|
mtx.vout.resize(1);
|
||||||
|
auto value = SetFoundersRewardAndGetMinerValue(ctx);
|
||||||
|
|
||||||
// Now fill in the miner's output.
|
// Now fill in the miner's output.
|
||||||
mtx.vout[0].nValue = value;
|
mtx.vout[0] = CTxOut(value, coinbaseScript->reserveScript);
|
||||||
mtx.vout[0].scriptPubKey = coinbaseScript->reserveScript;
|
|
||||||
|
if (mtx.vShieldedOutput.size() > 0) {
|
||||||
|
ComputeBindingSig(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
librustzcash_sapling_proving_ctx_free(ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -540,7 +621,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const MinerAddre
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false))
|
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false))
|
||||||
throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed");
|
throw std::runtime_error(std::string("CreateNewBlock(): TestBlockValidity failed: ") + state.GetRejectReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pblocktemplate.release();
|
return pblocktemplate.release();
|
||||||
|
@ -565,9 +646,11 @@ class MinerAddressScript : public CReserveScript
|
||||||
|
|
||||||
void GetMinerAddress(MinerAddress &minerAddress)
|
void GetMinerAddress(MinerAddress &minerAddress)
|
||||||
{
|
{
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// Try a transparent address first
|
// Try a transparent address first
|
||||||
auto mAddrArg = GetArg("-mineraddress", "");
|
auto mAddrArg = GetArg("-mineraddress", "");
|
||||||
CTxDestination addr = DecodeDestination(mAddrArg);
|
CTxDestination addr = keyIO.DecodeDestination(mAddrArg);
|
||||||
if (IsValidDestination(addr)) {
|
if (IsValidDestination(addr)) {
|
||||||
boost::shared_ptr<MinerAddressScript> mAddr(new MinerAddressScript());
|
boost::shared_ptr<MinerAddressScript> mAddr(new MinerAddressScript());
|
||||||
CKeyID keyID = boost::get<CKeyID>(addr);
|
CKeyID keyID = boost::get<CKeyID>(addr);
|
||||||
|
@ -576,7 +659,7 @@ void GetMinerAddress(MinerAddress &minerAddress)
|
||||||
minerAddress = mAddr;
|
minerAddress = mAddr;
|
||||||
} else {
|
} else {
|
||||||
// Try a Sapling address
|
// Try a Sapling address
|
||||||
auto zaddr = DecodePaymentAddress(mAddrArg);
|
auto zaddr = keyIO.DecodePaymentAddress(mAddrArg);
|
||||||
if (IsValidPaymentAddress(zaddr)) {
|
if (IsValidPaymentAddress(zaddr)) {
|
||||||
if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
|
if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
|
||||||
minerAddress = boost::get<libzcash::SaplingPaymentAddress>(zaddr);
|
minerAddress = boost::get<libzcash::SaplingPaymentAddress>(zaddr);
|
||||||
|
|
|
@ -143,6 +143,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||||
result.pushKV("version", block.nVersion);
|
result.pushKV("version", block.nVersion);
|
||||||
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
|
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue deltas(UniValue::VARR);
|
UniValue deltas(UniValue::VARR);
|
||||||
for (unsigned int i = 0; i < block.vtx.size(); i++) {
|
for (unsigned int i = 0; i < block.vtx.size(); i++) {
|
||||||
const CTransaction &tx = block.vtx[i];
|
const CTransaction &tx = block.vtx[i];
|
||||||
|
@ -165,7 +166,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||||
}
|
}
|
||||||
CTxDestination dest = DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash);
|
CTxDestination dest = DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash);
|
||||||
if (IsValidDestination(dest)) {
|
if (IsValidDestination(dest)) {
|
||||||
delta.pushKV("address", EncodeDestination(dest));
|
delta.pushKV("address", keyIO.EncodeDestination(dest));
|
||||||
}
|
}
|
||||||
delta.pushKV("satoshis", -1 * spentInfo.satoshis);
|
delta.pushKV("satoshis", -1 * spentInfo.satoshis);
|
||||||
delta.pushKV("index", (int)j);
|
delta.pushKV("index", (int)j);
|
||||||
|
@ -190,9 +191,9 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||||
dest = CKeyID(addrhash);
|
dest = CKeyID(addrhash);
|
||||||
}
|
}
|
||||||
if (IsValidDestination(dest)) {
|
if (IsValidDestination(dest)) {
|
||||||
delta.pushKV("address", EncodeDestination(dest));
|
delta.pushKV("address", keyIO.EncodeDestination(dest));
|
||||||
}
|
}
|
||||||
delta.pushKV("address", EncodeDestination(dest));
|
delta.pushKV("address", keyIO.EncodeDestination(dest));
|
||||||
delta.pushKV("satoshis", out.nValue);
|
delta.pushKV("satoshis", out.nValue);
|
||||||
delta.pushKV("index", (int)k);
|
delta.pushKV("index", (int)k);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/funding.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#ifdef ENABLE_MINING
|
#ifdef ENABLE_MINING
|
||||||
|
@ -527,6 +528,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
// TestBlockValidity only supports blocks built on the current Tip
|
// TestBlockValidity only supports blocks built on the current Tip
|
||||||
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
||||||
return "inconclusive-not-best-prevblk";
|
return "inconclusive-not-best-prevblk";
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
TestBlockValidity(state, Params(), block, pindexPrev, false, true);
|
TestBlockValidity(state, Params(), block, pindexPrev, false, true);
|
||||||
return BIP22ValidationResult(state);
|
return BIP22ValidationResult(state);
|
||||||
|
@ -877,8 +879,15 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp)
|
||||||
"1. height (numeric, optional) The block height. If not provided, defaults to the current height of the chain.\n"
|
"1. height (numeric, optional) The block height. If not provided, defaults to the current height of the chain.\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"miner\" : x.xxx (numeric) The mining reward amount in " + CURRENCY_UNIT + ".\n"
|
" \"miner\" : x.xxx, (numeric) The mining reward amount in " + CURRENCY_UNIT + ".\n"
|
||||||
" \"founders\" : x.xxx (numeric) The founders reward amount in " + CURRENCY_UNIT + ".\n"
|
" \"founders\" : x.xxx, (numeric) The founders' reward amount in " + CURRENCY_UNIT + ".\n"
|
||||||
|
" \"fundingstreams\" : [ (array) An array of funding stream descriptions (present only when Canopy has activated).\n"
|
||||||
|
" {\n"
|
||||||
|
" \"recipient\" : \"...\", (string) A description of the funding stream recipient.\n"
|
||||||
|
" \"specification\" : \"url\", (string) A URL for the specification of this funding stream.\n"
|
||||||
|
" \"value\" : x.xxx (numeric) The funding stream amount in " + CURRENCY_UNIT + ".\n"
|
||||||
|
" }, ...\n"
|
||||||
|
" ]\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
+ HelpExampleCli("getblocksubsidy", "1000")
|
+ HelpExampleCli("getblocksubsidy", "1000")
|
||||||
|
@ -890,14 +899,32 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp)
|
||||||
if (nHeight < 0)
|
if (nHeight < 0)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||||
|
|
||||||
CAmount nReward = GetBlockSubsidy(nHeight, Params().GetConsensus());
|
auto consensus = Params().GetConsensus();
|
||||||
|
CAmount nBlockSubsidy = GetBlockSubsidy(nHeight, consensus);
|
||||||
|
CAmount nMinerReward = nBlockSubsidy;
|
||||||
CAmount nFoundersReward = 0;
|
CAmount nFoundersReward = 0;
|
||||||
if ((nHeight > 0) && (nHeight <= Params().GetConsensus().GetLastFoundersRewardBlockHeight(nHeight))) {
|
bool canopyActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_CANOPY);
|
||||||
nFoundersReward = nReward/5;
|
|
||||||
nReward -= nFoundersReward;
|
|
||||||
}
|
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.pushKV("miner", ValueFromAmount(nReward));
|
if (canopyActive) {
|
||||||
|
UniValue fundingstreams(UniValue::VARR);
|
||||||
|
auto fsinfos = Consensus::GetActiveFundingStreams(nHeight, consensus);
|
||||||
|
for (auto fsinfo : fsinfos) {
|
||||||
|
CAmount nStreamAmount = fsinfo.Value(nBlockSubsidy);
|
||||||
|
nMinerReward -= nStreamAmount;
|
||||||
|
|
||||||
|
UniValue fsobj(UniValue::VOBJ);
|
||||||
|
fsobj.pushKV("recipient", fsinfo.recipient);
|
||||||
|
fsobj.pushKV("specification", fsinfo.specification);
|
||||||
|
fsobj.pushKV("value", ValueFromAmount(nStreamAmount));
|
||||||
|
fundingstreams.push_back(fsobj);
|
||||||
|
}
|
||||||
|
result.pushKV("fundingstreams", fundingstreams);
|
||||||
|
} else if (nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight)) {
|
||||||
|
nFoundersReward = nBlockSubsidy/5;
|
||||||
|
nMinerReward -= nFoundersReward;
|
||||||
|
}
|
||||||
|
result.pushKV("miner", ValueFromAmount(nMinerReward));
|
||||||
result.pushKV("founders", ValueFromAmount(nFoundersReward));
|
result.pushKV("founders", ValueFromAmount(nFoundersReward));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue operator()(const CScriptID &scriptID) const {
|
UniValue operator()(const CScriptID &scriptID) const {
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
CScript subscript;
|
CScript subscript;
|
||||||
obj.pushKV("isscript", true);
|
obj.pushKV("isscript", true);
|
||||||
|
@ -139,7 +140,7 @@ public:
|
||||||
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
|
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
|
||||||
UniValue a(UniValue::VARR);
|
UniValue a(UniValue::VARR);
|
||||||
for (const CTxDestination& addr : addresses) {
|
for (const CTxDestination& addr : addresses) {
|
||||||
a.push_back(EncodeDestination(addr));
|
a.push_back(keyIO.EncodeDestination(addr));
|
||||||
}
|
}
|
||||||
obj.pushKV("addresses", a);
|
obj.pushKV("addresses", a);
|
||||||
if (whichType == TX_MULTISIG)
|
if (whichType == TX_MULTISIG)
|
||||||
|
@ -180,14 +181,15 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination dest = keyIO.DecodeDestination(params[0].get_str());
|
||||||
bool isValid = IsValidDestination(dest);
|
bool isValid = IsValidDestination(dest);
|
||||||
|
|
||||||
UniValue ret(UniValue::VOBJ);
|
UniValue ret(UniValue::VOBJ);
|
||||||
ret.pushKV("isvalid", isValid);
|
ret.pushKV("isvalid", isValid);
|
||||||
if (isValid)
|
if (isValid)
|
||||||
{
|
{
|
||||||
std::string currentAddress = EncodeDestination(dest);
|
std::string currentAddress = keyIO.EncodeDestination(dest);
|
||||||
ret.pushKV("address", currentAddress);
|
ret.pushKV("address", currentAddress);
|
||||||
|
|
||||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||||
|
@ -271,8 +273,9 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
string strAddress = params[0].get_str();
|
string strAddress = params[0].get_str();
|
||||||
auto address = DecodePaymentAddress(strAddress);
|
auto address = keyIO.DecodePaymentAddress(strAddress);
|
||||||
bool isValid = IsValidPaymentAddress(address);
|
bool isValid = IsValidPaymentAddress(address);
|
||||||
|
|
||||||
UniValue ret(UniValue::VOBJ);
|
UniValue ret(UniValue::VOBJ);
|
||||||
|
@ -304,6 +307,9 @@ CScript _createmultisig_redeemScript(const UniValue& params)
|
||||||
"(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
|
"(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
|
||||||
if (keys.size() > 16)
|
if (keys.size() > 16)
|
||||||
throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
|
throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
std::vector<CPubKey> pubkeys;
|
std::vector<CPubKey> pubkeys;
|
||||||
pubkeys.resize(keys.size());
|
pubkeys.resize(keys.size());
|
||||||
for (unsigned int i = 0; i < keys.size(); i++)
|
for (unsigned int i = 0; i < keys.size(); i++)
|
||||||
|
@ -311,7 +317,7 @@ CScript _createmultisig_redeemScript(const UniValue& params)
|
||||||
const std::string& ks = keys[i].get_str();
|
const std::string& ks = keys[i].get_str();
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
// Case 1: Bitcoin address and we have full public key:
|
// Case 1: Bitcoin address and we have full public key:
|
||||||
CTxDestination dest = DecodeDestination(ks);
|
CTxDestination dest = keyIO.DecodeDestination(ks);
|
||||||
if (pwalletMain && IsValidDestination(dest)) {
|
if (pwalletMain && IsValidDestination(dest)) {
|
||||||
const CKeyID *keyID = boost::get<CKeyID>(&dest);
|
const CKeyID *keyID = boost::get<CKeyID>(&dest);
|
||||||
if (!keyID) {
|
if (!keyID) {
|
||||||
|
@ -385,8 +391,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
|
||||||
CScript inner = _createmultisig_redeemScript(params);
|
CScript inner = _createmultisig_redeemScript(params);
|
||||||
CScriptID innerID(inner);
|
CScriptID innerID(inner);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.pushKV("address", EncodeDestination(innerID));
|
result.pushKV("address", keyIO.EncodeDestination(innerID));
|
||||||
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
|
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -421,7 +428,8 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
|
||||||
string strSign = params[1].get_str();
|
string strSign = params[1].get_str();
|
||||||
string strMessage = params[2].get_str();
|
string strMessage = params[2].get_str();
|
||||||
|
|
||||||
CTxDestination destination = DecodeDestination(strAddress);
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination destination = keyIO.DecodeDestination(strAddress);
|
||||||
if (!IsValidDestination(destination)) {
|
if (!IsValidDestination(destination)) {
|
||||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
|
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
|
||||||
}
|
}
|
||||||
|
@ -506,10 +514,11 @@ UniValue getexperimentalfeatures(const UniValue& params, bool fHelp)
|
||||||
static bool getAddressFromIndex(
|
static bool getAddressFromIndex(
|
||||||
int type, const uint160 &hash, std::string &address)
|
int type, const uint160 &hash, std::string &address)
|
||||||
{
|
{
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (type == CScript::P2SH) {
|
if (type == CScript::P2SH) {
|
||||||
address = EncodeDestination(CScriptID(hash));
|
address = keyIO.EncodeDestination(CScriptID(hash));
|
||||||
} else if (type == CScript::P2PKH) {
|
} else if (type == CScript::P2PKH) {
|
||||||
address = EncodeDestination(CKeyID(hash));
|
address = keyIO.EncodeDestination(CKeyID(hash));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -560,8 +569,10 @@ static bool getAddressesFromParams(
|
||||||
} else {
|
} else {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (const auto& it : param_addresses) {
|
for (const auto& it : param_addresses) {
|
||||||
CTxDestination address = DecodeDestination(it);
|
CTxDestination address = keyIO.DecodeDestination(it);
|
||||||
uint160 hashBytes;
|
uint160 hashBytes;
|
||||||
int type = 0;
|
int type = 0;
|
||||||
if (!getIndexKey(address, hashBytes, type)) {
|
if (!getIndexKey(address, hashBytes, type)) {
|
||||||
|
|
|
@ -51,9 +51,10 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
|
||||||
out.pushKV("reqSigs", nRequired);
|
out.pushKV("reqSigs", nRequired);
|
||||||
out.pushKV("type", GetTxnOutputType(type));
|
out.pushKV("type", GetTxnOutputType(type));
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue a(UniValue::VARR);
|
UniValue a(UniValue::VARR);
|
||||||
for (const CTxDestination& addr : addresses) {
|
for (const CTxDestination& addr : addresses) {
|
||||||
a.push_back(EncodeDestination(addr));
|
a.push_back(keyIO.EncodeDestination(addr));
|
||||||
}
|
}
|
||||||
out.pushKV("addresses", a);
|
out.pushKV("addresses", a);
|
||||||
}
|
}
|
||||||
|
@ -161,6 +162,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||||
if (tx.fOverwintered) {
|
if (tx.fOverwintered) {
|
||||||
entry.pushKV("expiryheight", (int64_t)tx.nExpiryHeight);
|
entry.pushKV("expiryheight", (int64_t)tx.nExpiryHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue vin(UniValue::VARR);
|
UniValue vin(UniValue::VARR);
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||||
UniValue in(UniValue::VOBJ);
|
UniValue in(UniValue::VOBJ);
|
||||||
|
@ -184,7 +187,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||||
CTxDestination dest =
|
CTxDestination dest =
|
||||||
DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash);
|
DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash);
|
||||||
if (IsValidDestination(dest)) {
|
if (IsValidDestination(dest)) {
|
||||||
in.pushKV("address", EncodeDestination(dest));
|
in.pushKV("address", keyIO.EncodeDestination(dest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,10 +588,11 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
|
||||||
rawTx.vin.push_back(in);
|
rawTx.vin.push_back(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
std::set<CTxDestination> destinations;
|
std::set<CTxDestination> destinations;
|
||||||
vector<string> addrList = sendTo.getKeys();
|
vector<string> addrList = sendTo.getKeys();
|
||||||
for (const std::string& name_ : addrList) {
|
for (const std::string& name_ : addrList) {
|
||||||
CTxDestination destination = DecodeDestination(name_);
|
CTxDestination destination = keyIO.DecodeDestination(name_);
|
||||||
if (!IsValidDestination(destination)) {
|
if (!IsValidDestination(destination)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
|
||||||
}
|
}
|
||||||
|
@ -740,7 +744,8 @@ UniValue decodescript(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
ScriptPubKeyToJSON(script, r, false);
|
ScriptPubKeyToJSON(script, r, false);
|
||||||
|
|
||||||
r.pushKV("p2sh", EncodeDestination(CScriptID(script)));
|
KeyIO keyIO(Params());
|
||||||
|
r.pushKV("p2sh", keyIO.EncodeDestination(CScriptID(script)));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,6 +870,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||||
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
bool fGivenKeys = false;
|
bool fGivenKeys = false;
|
||||||
CBasicKeyStore tempKeystore;
|
CBasicKeyStore tempKeystore;
|
||||||
if (params.size() > 2 && !params[2].isNull()) {
|
if (params.size() > 2 && !params[2].isNull()) {
|
||||||
|
@ -872,7 +879,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||||
UniValue keys = params[2].get_array();
|
UniValue keys = params[2].get_array();
|
||||||
for (size_t idx = 0; idx < keys.size(); idx++) {
|
for (size_t idx = 0; idx < keys.size(); idx++) {
|
||||||
UniValue k = keys[idx];
|
UniValue k = keys[idx];
|
||||||
CKey key = DecodeSecret(k.get_str());
|
CKey key = keyIO.DecodeSecret(k.get_str());
|
||||||
if (!key.IsValid())
|
if (!key.IsValid())
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
||||||
tempKeystore.AddKey(key);
|
tempKeystore.AddKey(key);
|
||||||
|
|
|
@ -100,26 +100,28 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
|
||||||
} else {
|
} else {
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (isPrivkey) {
|
if (isPrivkey) {
|
||||||
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
|
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
|
||||||
// Must be valid private key
|
// Must be valid private key
|
||||||
privkey = DecodeSecret(exp_base58string);
|
privkey = keyIO.DecodeSecret(exp_base58string);
|
||||||
BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
|
BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
|
||||||
BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
|
BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
|
||||||
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
|
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
|
||||||
|
|
||||||
// Private key must be invalid public key
|
// Private key must be invalid public key
|
||||||
destination = DecodeDestination(exp_base58string);
|
destination = keyIO.DecodeDestination(exp_base58string);
|
||||||
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
|
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
|
||||||
} else {
|
} else {
|
||||||
// Must be valid public key
|
// Must be valid public key
|
||||||
destination = DecodeDestination(exp_base58string);
|
destination = keyIO.DecodeDestination(exp_base58string);
|
||||||
CScript script = GetScriptForDestination(destination);
|
CScript script = GetScriptForDestination(destination);
|
||||||
BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
|
BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
|
||||||
BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
|
BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
|
||||||
|
|
||||||
// Public key must be invalid private key
|
// Public key must be invalid private key
|
||||||
privkey = DecodeSecret(exp_base58string);
|
privkey = keyIO.DecodeSecret(exp_base58string);
|
||||||
BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest);
|
BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,17 +150,19 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
|
||||||
} else {
|
} else {
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (isPrivkey) {
|
if (isPrivkey) {
|
||||||
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
|
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
|
||||||
CKey key;
|
CKey key;
|
||||||
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
|
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
|
||||||
assert(key.IsValid());
|
assert(key.IsValid());
|
||||||
BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest);
|
BOOST_CHECK_MESSAGE(keyIO.EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest);
|
||||||
} else {
|
} else {
|
||||||
CTxDestination dest;
|
CTxDestination dest;
|
||||||
CScript exp_script(exp_payload.begin(), exp_payload.end());
|
CScript exp_script(exp_payload.begin(), exp_payload.end());
|
||||||
ExtractDestination(exp_script, dest);
|
ExtractDestination(exp_script, dest);
|
||||||
std::string address = EncodeDestination(dest);
|
std::string address = keyIO.EncodeDestination(dest);
|
||||||
BOOST_CHECK_EQUAL(address, exp_base58string);
|
BOOST_CHECK_EQUAL(address, exp_base58string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,6 +177,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
|
||||||
CKey privkey;
|
CKey privkey;
|
||||||
CTxDestination destination;
|
CTxDestination destination;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (size_t idx = 0; idx < tests.size(); idx++) {
|
for (size_t idx = 0; idx < tests.size(); idx++) {
|
||||||
UniValue test = tests[idx];
|
UniValue test = tests[idx];
|
||||||
std::string strTest = test.write();
|
std::string strTest = test.write();
|
||||||
|
@ -184,9 +189,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
|
||||||
std::string exp_base58string = test[0].get_str();
|
std::string exp_base58string = test[0].get_str();
|
||||||
|
|
||||||
// must be invalid as public and as private key
|
// must be invalid as public and as private key
|
||||||
destination = DecodeDestination(exp_base58string);
|
destination = keyIO.DecodeDestination(exp_base58string);
|
||||||
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
|
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
|
||||||
privkey = DecodeSecret(exp_base58string);
|
privkey = keyIO.DecodeSecret(exp_base58string);
|
||||||
BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest);
|
BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,18 +84,19 @@ void RunTest(const TestVector &test) {
|
||||||
CExtPubKey pubkey;
|
CExtPubKey pubkey;
|
||||||
key.SetMaster(&seed[0], seed.size());
|
key.SetMaster(&seed[0], seed.size());
|
||||||
pubkey = key.Neuter();
|
pubkey = key.Neuter();
|
||||||
|
KeyIO keyIO(Params());
|
||||||
BOOST_FOREACH(const TestDerivation &derive, test.vDerive) {
|
BOOST_FOREACH(const TestDerivation &derive, test.vDerive) {
|
||||||
unsigned char data[74];
|
unsigned char data[74];
|
||||||
key.Encode(data);
|
key.Encode(data);
|
||||||
pubkey.Encode(data);
|
pubkey.Encode(data);
|
||||||
|
|
||||||
// Test private key
|
// Test private key
|
||||||
BOOST_CHECK(EncodeExtKey(key) == derive.prv);
|
BOOST_CHECK(keyIO.EncodeExtKey(key) == derive.prv);
|
||||||
BOOST_CHECK(DecodeExtKey(derive.prv) == key); //ensure a base58 decoded key also matches
|
BOOST_CHECK(keyIO.DecodeExtKey(derive.prv) == key); //ensure a base58 decoded key also matches
|
||||||
|
|
||||||
// Test public key
|
// Test public key
|
||||||
BOOST_CHECK(EncodeExtPubKey(pubkey) == derive.pub);
|
BOOST_CHECK(keyIO.EncodeExtPubKey(pubkey) == derive.pub);
|
||||||
BOOST_CHECK(DecodeExtPubKey(derive.pub) == pubkey); //ensure a base58 decoded pubkey also matches
|
BOOST_CHECK(keyIO.DecodeExtPubKey(derive.pub) == pubkey); //ensure a base58 decoded pubkey also matches
|
||||||
|
|
||||||
// Derive new keys
|
// Derive new keys
|
||||||
CExtKey keyNew;
|
CExtKey keyNew;
|
||||||
|
|
|
@ -86,8 +86,9 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
|
BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
|
||||||
{
|
{
|
||||||
|
KeyIO keyIO(Params());
|
||||||
std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
|
std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
|
||||||
CKey key = DecodeSecret(strSecret);
|
CKey key = keyIO.DecodeSecret(strSecret);
|
||||||
CPubKey pubkey = key.GetPubKey();
|
CPubKey pubkey = key.GetPubKey();
|
||||||
vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
|
vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ void dumpKeyInfo(uint256 privkey)
|
||||||
memcpy(&sec[0], &secret[0], 32);
|
memcpy(&sec[0], &secret[0], 32);
|
||||||
printf(" * secret (hex): %s\n", HexStr(sec).c_str());
|
printf(" * secret (hex): %s\n", HexStr(sec).c_str());
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (int nCompressed=0; nCompressed<2; nCompressed++)
|
for (int nCompressed=0; nCompressed<2; nCompressed++)
|
||||||
{
|
{
|
||||||
bool fCompressed = nCompressed == 1;
|
bool fCompressed = nCompressed == 1;
|
||||||
|
@ -57,7 +58,7 @@ void dumpKeyInfo(uint256 privkey)
|
||||||
key.SetSecret(secret, fCompressed);
|
key.SetSecret(secret, fCompressed);
|
||||||
vector<unsigned char> vchPubKey = key.GetPubKey();
|
vector<unsigned char> vchPubKey = key.GetPubKey();
|
||||||
printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str());
|
printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str());
|
||||||
printf(" * address (base58): %s\n", EncodeDestination(vchPubKey).c_str());
|
printf(" * address (base58): %s\n", keyIO.EncodeDestination(vchPubKey).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,15 +68,16 @@ BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(key_test1)
|
BOOST_AUTO_TEST_CASE(key_test1)
|
||||||
{
|
{
|
||||||
CKey key1 = DecodeSecret(strSecret1);
|
KeyIO keyIO(Params());
|
||||||
|
CKey key1 = keyIO.DecodeSecret(strSecret1);
|
||||||
BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
|
BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
|
||||||
CKey key2 = DecodeSecret(strSecret2);
|
CKey key2 = keyIO.DecodeSecret(strSecret2);
|
||||||
BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
|
BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
|
||||||
CKey key1C = DecodeSecret(strSecret1C);
|
CKey key1C = keyIO.DecodeSecret(strSecret1C);
|
||||||
BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
|
BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
|
||||||
CKey key2C = DecodeSecret(strSecret2C);
|
CKey key2C = keyIO.DecodeSecret(strSecret2C);
|
||||||
BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
|
BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
|
||||||
CKey bad_key = DecodeSecret(strAddressBad);
|
CKey bad_key = keyIO.DecodeSecret(strAddressBad);
|
||||||
BOOST_CHECK(!bad_key.IsValid());
|
BOOST_CHECK(!bad_key.IsValid());
|
||||||
|
|
||||||
CPubKey pubkey1 = key1. GetPubKey();
|
CPubKey pubkey1 = key1. GetPubKey();
|
||||||
|
@ -103,10 +105,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
||||||
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
|
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
|
||||||
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
|
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
|
||||||
|
|
||||||
BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
|
BOOST_CHECK(keyIO.DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
|
||||||
BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
|
BOOST_CHECK(keyIO.DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
|
||||||
BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
|
BOOST_CHECK(keyIO.DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
|
||||||
BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
|
BOOST_CHECK(keyIO.DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
|
||||||
|
|
||||||
for (int n=0; n<16; n++)
|
for (int n=0; n<16; n++)
|
||||||
{
|
{
|
||||||
|
@ -189,15 +191,16 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(zc_address_test)
|
BOOST_AUTO_TEST_CASE(zc_address_test)
|
||||||
{
|
{
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (size_t i = 0; i < 1000; i++) {
|
for (size_t i = 0; i < 1000; i++) {
|
||||||
auto sk = SproutSpendingKey::random();
|
auto sk = SproutSpendingKey::random();
|
||||||
{
|
{
|
||||||
string sk_string = EncodeSpendingKey(sk);
|
string sk_string = keyIO.EncodeSpendingKey(sk);
|
||||||
|
|
||||||
BOOST_CHECK(sk_string[0] == 'S');
|
BOOST_CHECK(sk_string[0] == 'S');
|
||||||
BOOST_CHECK(sk_string[1] == 'K');
|
BOOST_CHECK(sk_string[1] == 'K');
|
||||||
|
|
||||||
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string);
|
||||||
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
||||||
BOOST_ASSERT(boost::get<SproutSpendingKey>(&spendingkey2) != nullptr);
|
BOOST_ASSERT(boost::get<SproutSpendingKey>(&spendingkey2) != nullptr);
|
||||||
auto sk2 = boost::get<SproutSpendingKey>(spendingkey2);
|
auto sk2 = boost::get<SproutSpendingKey>(spendingkey2);
|
||||||
|
@ -206,12 +209,12 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
|
||||||
{
|
{
|
||||||
auto addr = sk.address();
|
auto addr = sk.address();
|
||||||
|
|
||||||
std::string addr_string = EncodePaymentAddress(addr);
|
std::string addr_string = keyIO.EncodePaymentAddress(addr);
|
||||||
|
|
||||||
BOOST_CHECK(addr_string[0] == 'z');
|
BOOST_CHECK(addr_string[0] == 'z');
|
||||||
BOOST_CHECK(addr_string[1] == 'c');
|
BOOST_CHECK(addr_string[1] == 'c');
|
||||||
|
|
||||||
auto paymentaddr2 = DecodePaymentAddress(addr_string);
|
auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string);
|
||||||
BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2));
|
BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2));
|
||||||
|
|
||||||
BOOST_ASSERT(boost::get<SproutPaymentAddress>(&paymentaddr2) != nullptr);
|
BOOST_ASSERT(boost::get<SproutPaymentAddress>(&paymentaddr2) != nullptr);
|
||||||
|
@ -228,13 +231,14 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
|
||||||
|
|
||||||
auto m = GetTestMasterSaplingSpendingKey();
|
auto m = GetTestMasterSaplingSpendingKey();
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (uint32_t i = 0; i < 1000; i++) {
|
for (uint32_t i = 0; i < 1000; i++) {
|
||||||
auto sk = m.Derive(i);
|
auto sk = m.Derive(i);
|
||||||
{
|
{
|
||||||
std::string sk_string = EncodeSpendingKey(sk);
|
std::string sk_string = keyIO.EncodeSpendingKey(sk);
|
||||||
BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)) == 0);
|
BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)) == 0);
|
||||||
|
|
||||||
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string);
|
||||||
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
||||||
|
|
||||||
BOOST_ASSERT(boost::get<SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
BOOST_ASSERT(boost::get<SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
||||||
|
@ -244,10 +248,10 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
|
||||||
{
|
{
|
||||||
auto addr = sk.DefaultAddress();
|
auto addr = sk.DefaultAddress();
|
||||||
|
|
||||||
std::string addr_string = EncodePaymentAddress(addr);
|
std::string addr_string = keyIO.EncodePaymentAddress(addr);
|
||||||
BOOST_CHECK(addr_string.compare(0, 15, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
BOOST_CHECK(addr_string.compare(0, 15, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
||||||
|
|
||||||
auto paymentaddr2 = DecodePaymentAddress(addr_string);
|
auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string);
|
||||||
BOOST_CHECK(IsValidPaymentAddress(paymentaddr2));
|
BOOST_CHECK(IsValidPaymentAddress(paymentaddr2));
|
||||||
|
|
||||||
BOOST_ASSERT(boost::get<SaplingPaymentAddress>(&paymentaddr2) != nullptr);
|
BOOST_ASSERT(boost::get<SaplingPaymentAddress>(&paymentaddr2) != nullptr);
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
#define NO_MEMO {{0xF6}}
|
||||||
|
|
||||||
struct SpendDescriptionInfo {
|
struct SpendDescriptionInfo {
|
||||||
libzcash::SaplingExpandedSpendingKey expsk;
|
libzcash::SaplingExpandedSpendingKey expsk;
|
||||||
libzcash::SaplingNote note;
|
libzcash::SaplingNote note;
|
||||||
|
@ -118,7 +120,7 @@ public:
|
||||||
uint256 ovk,
|
uint256 ovk,
|
||||||
libzcash::SaplingPaymentAddress to,
|
libzcash::SaplingPaymentAddress to,
|
||||||
CAmount value,
|
CAmount value,
|
||||||
std::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}});
|
std::array<unsigned char, ZC_MEMO_SIZE> memo = NO_MEMO);
|
||||||
|
|
||||||
// Throws if the anchor does not match the anchor used by
|
// Throws if the anchor does not match the anchor used by
|
||||||
// previously-added Sprout inputs.
|
// previously-added Sprout inputs.
|
||||||
|
@ -130,7 +132,7 @@ public:
|
||||||
void AddSproutOutput(
|
void AddSproutOutput(
|
||||||
libzcash::SproutPaymentAddress to,
|
libzcash::SproutPaymentAddress to,
|
||||||
CAmount value,
|
CAmount value,
|
||||||
std::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}});
|
std::array<unsigned char, ZC_MEMO_SIZE> memo = NO_MEMO);
|
||||||
|
|
||||||
// Assumes that the value correctly corresponds to the provided UTXO.
|
// Assumes that the value correctly corresponds to the provided UTXO.
|
||||||
void AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value);
|
void AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value);
|
||||||
|
|
|
@ -286,7 +286,8 @@ libzcash::SaplingExtendedSpendingKey GetTestMasterSaplingSpendingKey() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CKey AddTestCKeyToKeyStore(CBasicKeyStore& keyStore) {
|
CKey AddTestCKeyToKeyStore(CBasicKeyStore& keyStore) {
|
||||||
CKey tsk = DecodeSecret(T_SECRET_REGTEST);
|
KeyIO keyIO(Params());
|
||||||
|
CKey tsk = keyIO.DecodeSecret(T_SECRET_REGTEST);
|
||||||
keyStore.AddKey(tsk);
|
keyStore.AddKey(tsk);
|
||||||
return tsk;
|
return tsk;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,12 +91,13 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
|
||||||
builder_ = builder.get();
|
builder_ = builder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
toTaddr_ = DecodeDestination(std::get<0>(recipient));
|
KeyIO keyIO(Params());
|
||||||
|
toTaddr_ = keyIO.DecodeDestination(std::get<0>(recipient));
|
||||||
isToTaddr_ = IsValidDestination(toTaddr_);
|
isToTaddr_ = IsValidDestination(toTaddr_);
|
||||||
isToZaddr_ = false;
|
isToZaddr_ = false;
|
||||||
|
|
||||||
if (!isToTaddr_) {
|
if (!isToTaddr_) {
|
||||||
auto address = DecodePaymentAddress(std::get<0>(recipient));
|
auto address = keyIO.DecodePaymentAddress(std::get<0>(recipient));
|
||||||
if (IsValidPaymentAddress(address)) {
|
if (IsValidPaymentAddress(address)) {
|
||||||
isToZaddr_ = true;
|
isToZaddr_ = true;
|
||||||
toPaymentAddress_ = address;
|
toPaymentAddress_ = address;
|
||||||
|
@ -866,6 +867,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
|
||||||
arrOutputMap.push_back(static_cast<uint64_t>(outputMap[i]));
|
arrOutputMap.push_back(static_cast<uint64_t>(outputMap[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// !!! Payment disclosure START
|
// !!! Payment disclosure START
|
||||||
unsigned char buffer[32] = {0};
|
unsigned char buffer[32] = {0};
|
||||||
|
@ -883,7 +885,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
|
||||||
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
|
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
|
||||||
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
|
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
|
||||||
|
|
||||||
LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr));
|
LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), keyIO.EncodePaymentAddress(zaddr));
|
||||||
}
|
}
|
||||||
// !!! Payment disclosure END
|
// !!! Payment disclosure END
|
||||||
|
|
||||||
|
|
|
@ -192,9 +192,10 @@ CAmount AsyncRPCOperation_saplingmigration::chooseAmount(const CAmount& availabl
|
||||||
|
|
||||||
// Unless otherwise specified, the migration destination address is the address for Sapling account 0
|
// Unless otherwise specified, the migration destination address is the address for Sapling account 0
|
||||||
libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigrationDestAddress(const HDSeed& seed) {
|
libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigrationDestAddress(const HDSeed& seed) {
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (mapArgs.count("-migrationdestaddress")) {
|
if (mapArgs.count("-migrationdestaddress")) {
|
||||||
std::string migrationDestAddress = mapArgs["-migrationdestaddress"];
|
std::string migrationDestAddress = mapArgs["-migrationdestaddress"];
|
||||||
auto address = DecodePaymentAddress(migrationDestAddress);
|
auto address = keyIO.DecodePaymentAddress(migrationDestAddress);
|
||||||
auto saplingAddress = boost::get<libzcash::SaplingPaymentAddress>(&address);
|
auto saplingAddress = boost::get<libzcash::SaplingPaymentAddress>(&address);
|
||||||
assert(saplingAddress != nullptr); // This is checked in init.cpp
|
assert(saplingAddress != nullptr); // This is checked in init.cpp
|
||||||
return *saplingAddress;
|
return *saplingAddress;
|
||||||
|
|
|
@ -85,12 +85,14 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
|
||||||
builder_ = builder.get();
|
builder_ = builder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
fromtaddr_ = DecodeDestination(fromAddress);
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
|
fromtaddr_ = keyIO.DecodeDestination(fromAddress);
|
||||||
isfromtaddr_ = IsValidDestination(fromtaddr_);
|
isfromtaddr_ = IsValidDestination(fromtaddr_);
|
||||||
isfromzaddr_ = false;
|
isfromzaddr_ = false;
|
||||||
|
|
||||||
if (!isfromtaddr_) {
|
if (!isfromtaddr_) {
|
||||||
auto address = DecodePaymentAddress(fromAddress);
|
auto address = keyIO.DecodePaymentAddress(fromAddress);
|
||||||
if (IsValidPaymentAddress(address)) {
|
if (IsValidPaymentAddress(address)) {
|
||||||
// We don't need to lock on the wallet as spending key related methods are thread-safe
|
// We don't need to lock on the wallet as spending key related methods are thread-safe
|
||||||
if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), address)) {
|
if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), address)) {
|
||||||
|
@ -343,6 +345,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||||
LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total));
|
LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total));
|
||||||
LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee));
|
LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee));
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SCENARIO #0
|
* SCENARIO #0
|
||||||
|
@ -424,7 +427,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||||
auto value = r.amount;
|
auto value = r.amount;
|
||||||
auto hexMemo = r.memo;
|
auto hexMemo = r.memo;
|
||||||
|
|
||||||
auto addr = DecodePaymentAddress(address);
|
auto addr = keyIO.DecodePaymentAddress(address);
|
||||||
assert(boost::get<libzcash::SaplingPaymentAddress>(&addr) != nullptr);
|
assert(boost::get<libzcash::SaplingPaymentAddress>(&addr) != nullptr);
|
||||||
auto to = boost::get<libzcash::SaplingPaymentAddress>(addr);
|
auto to = boost::get<libzcash::SaplingPaymentAddress>(addr);
|
||||||
|
|
||||||
|
@ -438,7 +441,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||||
auto outputAddress = r.address;
|
auto outputAddress = r.address;
|
||||||
auto amount = r.amount;
|
auto amount = r.amount;
|
||||||
|
|
||||||
auto address = DecodeDestination(outputAddress);
|
auto address = keyIO.DecodeDestination(outputAddress);
|
||||||
builder_.AddTransparentOutput(address, amount);
|
builder_.AddTransparentOutput(address, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +586,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||||
std::string hexMemo = smr.memo;
|
std::string hexMemo = smr.memo;
|
||||||
zOutputsDeque.pop_front();
|
zOutputsDeque.pop_front();
|
||||||
|
|
||||||
PaymentAddress pa = DecodePaymentAddress(address);
|
PaymentAddress pa = keyIO.DecodePaymentAddress(address);
|
||||||
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
|
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
|
||||||
if (hexMemo.size() > 0) {
|
if (hexMemo.size() > 0) {
|
||||||
jso.memo = get_memo_from_hex_string(hexMemo);
|
jso.memo = get_memo_from_hex_string(hexMemo);
|
||||||
|
@ -845,7 +848,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||||
assert(value==0);
|
assert(value==0);
|
||||||
info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new
|
info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new
|
||||||
} else {
|
} else {
|
||||||
PaymentAddress pa = DecodePaymentAddress(address);
|
PaymentAddress pa = keyIO.DecodePaymentAddress(address);
|
||||||
// If we are here, we know we have no Sapling outputs.
|
// If we are here, we know we have no Sapling outputs.
|
||||||
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
|
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
|
||||||
if (hexMemo.size() > 0) {
|
if (hexMemo.size() > 0) {
|
||||||
|
@ -1145,6 +1148,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
|
||||||
arrOutputMap.push_back(static_cast<uint64_t>(outputMap[i]));
|
arrOutputMap.push_back(static_cast<uint64_t>(outputMap[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// !!! Payment disclosure START
|
// !!! Payment disclosure START
|
||||||
unsigned char buffer[32] = {0};
|
unsigned char buffer[32] = {0};
|
||||||
|
@ -1162,7 +1166,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
|
||||||
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
|
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
|
||||||
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
|
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
|
||||||
|
|
||||||
LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr));
|
LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), keyIO.EncodePaymentAddress(zaddr));
|
||||||
}
|
}
|
||||||
// !!! Payment disclosure END
|
// !!! Payment disclosure END
|
||||||
|
|
||||||
|
@ -1179,11 +1183,13 @@ void AsyncRPCOperation_sendmany::add_taddr_outputs_to_tx() {
|
||||||
|
|
||||||
CMutableTransaction rawTx(tx_);
|
CMutableTransaction rawTx(tx_);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
for (SendManyRecipient & r : t_outputs_) {
|
for (SendManyRecipient & r : t_outputs_) {
|
||||||
std::string outputAddress = r.address;
|
std::string outputAddress = r.address;
|
||||||
CAmount nAmount = r.amount;
|
CAmount nAmount = r.amount;
|
||||||
|
|
||||||
CTxDestination address = DecodeDestination(outputAddress);
|
CTxDestination address = keyIO.DecodeDestination(outputAddress);
|
||||||
if (!IsValidDestination(address)) {
|
if (!IsValidDestination(address)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid output address, not a valid taddr.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid output address, not a valid taddr.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,8 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the destination address is valid for this network i.e. not testnet being used on mainnet
|
// Check the destination address is valid for this network i.e. not testnet being used on mainnet
|
||||||
auto address = DecodePaymentAddress(toAddress);
|
KeyIO keyIO(Params());
|
||||||
|
auto address = keyIO.DecodePaymentAddress(toAddress);
|
||||||
if (IsValidPaymentAddress(address)) {
|
if (IsValidPaymentAddress(address)) {
|
||||||
tozaddr_ = address;
|
tozaddr_ = address;
|
||||||
} else {
|
} else {
|
||||||
|
@ -386,6 +387,8 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
|
||||||
arrOutputMap.push_back(static_cast<uint64_t>(outputMap[i]));
|
arrOutputMap.push_back(static_cast<uint64_t>(outputMap[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// !!! Payment disclosure START
|
// !!! Payment disclosure START
|
||||||
unsigned char buffer[32] = {0};
|
unsigned char buffer[32] = {0};
|
||||||
memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer
|
memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer
|
||||||
|
@ -402,7 +405,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
|
||||||
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
|
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
|
||||||
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
|
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));
|
||||||
|
|
||||||
LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr));
|
LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), keyIO.EncodePaymentAddress(zaddr));
|
||||||
}
|
}
|
||||||
// !!! Payment disclosure END
|
// !!! Payment disclosure END
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
std::string PaymentDisclosureInfo::ToString() const {
|
std::string PaymentDisclosureInfo::ToString() const {
|
||||||
|
KeyIO keyIO(Params());
|
||||||
return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=<omitted>, address=%s)",
|
return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=<omitted>, address=%s)",
|
||||||
version, esk.ToString(), EncodePaymentAddress(zaddr));
|
version, esk.ToString(), keyIO.EncodePaymentAddress(zaddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PaymentDisclosure::ToString() const {
|
std::string PaymentDisclosure::ToString() const {
|
||||||
|
@ -18,8 +19,9 @@ std::string PaymentDisclosure::ToString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PaymentDisclosurePayload::ToString() const {
|
std::string PaymentDisclosurePayload::ToString() const {
|
||||||
|
KeyIO keyIO(Params());
|
||||||
return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)",
|
return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)",
|
||||||
version, esk.ToString(), txid.ToString(), js, n, EncodePaymentAddress(zaddr), message);
|
version, esk.ToString(), txid.ToString(), js, n, keyIO.EncodePaymentAddress(zaddr), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message)
|
PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message)
|
||||||
|
|
|
@ -250,10 +250,12 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp)
|
||||||
errs.push_back("Payment disclosure signature does not match transaction signature");
|
errs.push_back("Payment disclosure signature does not match transaction signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// Check the payment address is valid
|
// Check the payment address is valid
|
||||||
SproutPaymentAddress zaddr = pd.payload.zaddr;
|
SproutPaymentAddress zaddr = pd.payload.zaddr;
|
||||||
{
|
{
|
||||||
o.pushKV("paymentAddress", EncodePaymentAddress(zaddr));
|
o.pushKV("paymentAddress", keyIO.EncodePaymentAddress(zaddr));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Decrypt the note to get value and memo field
|
// Decrypt the note to get value and memo field
|
||||||
|
|
|
@ -116,7 +116,9 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||||
if (params.size() > 2)
|
if (params.size() > 2)
|
||||||
fRescan = params[2].get_bool();
|
fRescan = params[2].get_bool();
|
||||||
|
|
||||||
CKey key = DecodeSecret(strSecret);
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
|
CKey key = keyIO.DecodeSecret(strSecret);
|
||||||
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
|
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
|
||||||
|
|
||||||
CPubKey pubkey = key.GetPubKey();
|
CPubKey pubkey = key.GetPubKey();
|
||||||
|
@ -128,7 +130,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
// Don't throw error in case a key is already there
|
// Don't throw error in case a key is already there
|
||||||
if (pwalletMain->HaveKey(vchAddress)) {
|
if (pwalletMain->HaveKey(vchAddress)) {
|
||||||
return EncodeDestination(vchAddress);
|
return keyIO.EncodeDestination(vchAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
|
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
|
||||||
|
@ -144,7 +146,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EncodeDestination(vchAddress);
|
return keyIO.EncodeDestination(vchAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportAddress(const CTxDestination& dest, const string& strLabel);
|
void ImportAddress(const CTxDestination& dest, const string& strLabel);
|
||||||
|
@ -227,7 +229,8 @@ UniValue importaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination dest = keyIO.DecodeDestination(params[0].get_str());
|
||||||
if (IsValidDestination(dest)) {
|
if (IsValidDestination(dest)) {
|
||||||
if (fP2SH) {
|
if (fP2SH) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
|
||||||
|
@ -373,6 +376,8 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys)
|
||||||
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
|
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
|
||||||
file.seekg(0, file.beg);
|
file.seekg(0, file.beg);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
|
pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
|
||||||
while (file.good()) {
|
while (file.good()) {
|
||||||
pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
|
pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
|
||||||
|
@ -388,7 +393,7 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys)
|
||||||
|
|
||||||
// Let's see if the address is a valid Zcash spending key
|
// Let's see if the address is a valid Zcash spending key
|
||||||
if (fImportZKeys) {
|
if (fImportZKeys) {
|
||||||
auto spendingkey = DecodeSpendingKey(vstr[0]);
|
auto spendingkey = keyIO.DecodeSpendingKey(vstr[0]);
|
||||||
int64_t nTime = DecodeDumpTime(vstr[1]);
|
int64_t nTime = DecodeDumpTime(vstr[1]);
|
||||||
// Only include hdKeypath and seedFpStr if we have both
|
// Only include hdKeypath and seedFpStr if we have both
|
||||||
boost::optional<std::string> hdKeypath = (vstr.size() > 3) ? boost::optional<std::string>(vstr[2]) : boost::none;
|
boost::optional<std::string> hdKeypath = (vstr.size() > 3) ? boost::optional<std::string>(vstr[2]) : boost::none;
|
||||||
|
@ -409,14 +414,14 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CKey key = DecodeSecret(vstr[0]);
|
CKey key = keyIO.DecodeSecret(vstr[0]);
|
||||||
if (!key.IsValid())
|
if (!key.IsValid())
|
||||||
continue;
|
continue;
|
||||||
CPubKey pubkey = key.GetPubKey();
|
CPubKey pubkey = key.GetPubKey();
|
||||||
assert(key.VerifyPubKey(pubkey));
|
assert(key.VerifyPubKey(pubkey));
|
||||||
CKeyID keyid = pubkey.GetID();
|
CKeyID keyid = pubkey.GetID();
|
||||||
if (pwalletMain->HaveKey(keyid)) {
|
if (pwalletMain->HaveKey(keyid)) {
|
||||||
LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
|
LogPrintf("Skipping import of %s (key already present)\n", keyIO.EncodeDestination(keyid));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int64_t nTime = DecodeDumpTime(vstr[1]);
|
int64_t nTime = DecodeDumpTime(vstr[1]);
|
||||||
|
@ -434,7 +439,7 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys)
|
||||||
fLabel = true;
|
fLabel = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrintf("Importing %s...\n", EncodeDestination(keyid));
|
LogPrintf("Importing %s...\n", keyIO.EncodeDestination(keyid));
|
||||||
if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
|
if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
|
||||||
fGood = false;
|
fGood = false;
|
||||||
continue;
|
continue;
|
||||||
|
@ -489,8 +494,10 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
EnsureWalletIsUnlocked();
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
std::string strAddress = params[0].get_str();
|
std::string strAddress = params[0].get_str();
|
||||||
CTxDestination dest = DecodeDestination(strAddress);
|
CTxDestination dest = keyIO.DecodeDestination(strAddress);
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
||||||
}
|
}
|
||||||
|
@ -502,7 +509,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
|
||||||
if (!pwalletMain->GetKey(*keyID, vchSecret)) {
|
if (!pwalletMain->GetKey(*keyID, vchSecret)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
|
||||||
}
|
}
|
||||||
return EncodeSecret(vchSecret);
|
return keyIO.EncodeSecret(vchSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -593,6 +600,8 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys)
|
||||||
mapKeyBirth.clear();
|
mapKeyBirth.clear();
|
||||||
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// produce output
|
// produce output
|
||||||
file << strprintf("# Wallet dump created by Zcash %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
|
file << strprintf("# Wallet dump created by Zcash %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
|
||||||
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
|
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
|
||||||
|
@ -609,15 +618,15 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys)
|
||||||
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
|
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
|
||||||
const CKeyID &keyid = it->second;
|
const CKeyID &keyid = it->second;
|
||||||
std::string strTime = EncodeDumpTime(it->first);
|
std::string strTime = EncodeDumpTime(it->first);
|
||||||
std::string strAddr = EncodeDestination(keyid);
|
std::string strAddr = keyIO.EncodeDestination(keyid);
|
||||||
CKey key;
|
CKey key;
|
||||||
if (pwalletMain->GetKey(keyid, key)) {
|
if (pwalletMain->GetKey(keyid, key)) {
|
||||||
if (pwalletMain->mapAddressBook.count(keyid)) {
|
if (pwalletMain->mapAddressBook.count(keyid)) {
|
||||||
file << strprintf("%s %s label=%s # addr=%s\n", EncodeSecret(key), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
|
file << strprintf("%s %s label=%s # addr=%s\n", keyIO.EncodeSecret(key), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
|
||||||
} else if (setKeyPool.count(keyid)) {
|
} else if (setKeyPool.count(keyid)) {
|
||||||
file << strprintf("%s %s reserve=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr);
|
file << strprintf("%s %s reserve=1 # addr=%s\n", keyIO.EncodeSecret(key), strTime, strAddr);
|
||||||
} else {
|
} else {
|
||||||
file << strprintf("%s %s change=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr);
|
file << strprintf("%s %s change=1 # addr=%s\n", keyIO.EncodeSecret(key), strTime, strAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -633,7 +642,7 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys)
|
||||||
libzcash::SproutSpendingKey key;
|
libzcash::SproutSpendingKey key;
|
||||||
if (pwalletMain->GetSproutSpendingKey(addr, key)) {
|
if (pwalletMain->GetSproutSpendingKey(addr, key)) {
|
||||||
std::string strTime = EncodeDumpTime(pwalletMain->mapSproutZKeyMetadata[addr].nCreateTime);
|
std::string strTime = EncodeDumpTime(pwalletMain->mapSproutZKeyMetadata[addr].nCreateTime);
|
||||||
file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr));
|
file << strprintf("%s %s # zaddr=%s\n", keyIO.EncodeSpendingKey(key), strTime, keyIO.EncodePaymentAddress(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::set<libzcash::SaplingPaymentAddress> saplingAddresses;
|
std::set<libzcash::SaplingPaymentAddress> saplingAddresses;
|
||||||
|
@ -649,9 +658,9 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys)
|
||||||
std::string strTime = EncodeDumpTime(keyMeta.nCreateTime);
|
std::string strTime = EncodeDumpTime(keyMeta.nCreateTime);
|
||||||
// Keys imported with z_importkey do not have zip32 metadata
|
// Keys imported with z_importkey do not have zip32 metadata
|
||||||
if (keyMeta.hdKeypath.empty() || keyMeta.seedFp.IsNull()) {
|
if (keyMeta.hdKeypath.empty() || keyMeta.seedFp.IsNull()) {
|
||||||
file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(extsk), strTime, EncodePaymentAddress(addr));
|
file << strprintf("%s %s # zaddr=%s\n", keyIO.EncodeSpendingKey(extsk), strTime, keyIO.EncodePaymentAddress(addr));
|
||||||
} else {
|
} else {
|
||||||
file << strprintf("%s %s %s %s # zaddr=%s\n", EncodeSpendingKey(extsk), strTime, keyMeta.hdKeypath, keyMeta.seedFp.GetHex(), EncodePaymentAddress(addr));
|
file << strprintf("%s %s %s %s # zaddr=%s\n", keyIO.EncodeSpendingKey(extsk), strTime, keyMeta.hdKeypath, keyMeta.seedFp.GetHex(), keyIO.EncodePaymentAddress(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -737,8 +746,9 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
string strSecret = params[0].get_str();
|
string strSecret = params[0].get_str();
|
||||||
auto spendingkey = DecodeSpendingKey(strSecret);
|
auto spendingkey = keyIO.DecodeSpendingKey(strSecret);
|
||||||
if (!IsValidSpendingKey(spendingkey)) {
|
if (!IsValidSpendingKey(spendingkey)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||||
}
|
}
|
||||||
|
@ -746,7 +756,7 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
||||||
auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromSpendingKey{}, spendingkey);
|
auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromSpendingKey{}, spendingkey);
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.pushKV("type", addrInfo.first);
|
result.pushKV("type", addrInfo.first);
|
||||||
result.pushKV("address", EncodePaymentAddress(addrInfo.second));
|
result.pushKV("address", keyIO.EncodePaymentAddress(addrInfo.second));
|
||||||
|
|
||||||
// Sapling support
|
// Sapling support
|
||||||
auto addResult = boost::apply_visitor(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey);
|
auto addResult = boost::apply_visitor(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey);
|
||||||
|
@ -831,8 +841,9 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
string strVKey = params[0].get_str();
|
string strVKey = params[0].get_str();
|
||||||
auto viewingkey = DecodeViewingKey(strVKey);
|
auto viewingkey = keyIO.DecodeViewingKey(strVKey);
|
||||||
if (!IsValidViewingKey(viewingkey)) {
|
if (!IsValidViewingKey(viewingkey)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
|
||||||
}
|
}
|
||||||
|
@ -840,7 +851,7 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
|
||||||
auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromViewingKey{}, viewingkey);
|
auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromViewingKey{}, viewingkey);
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.pushKV("type", addrInfo.first);
|
result.pushKV("type", addrInfo.first);
|
||||||
result.pushKV("address", EncodePaymentAddress(addrInfo.second));
|
result.pushKV("address", keyIO.EncodePaymentAddress(addrInfo.second));
|
||||||
|
|
||||||
auto addResult = boost::apply_visitor(AddViewingKeyToWallet(pwalletMain), viewingkey);
|
auto addResult = boost::apply_visitor(AddViewingKeyToWallet(pwalletMain), viewingkey);
|
||||||
if (addResult == SpendingKeyExists) {
|
if (addResult == SpendingKeyExists) {
|
||||||
|
@ -889,7 +900,8 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
string strAddress = params[0].get_str();
|
string strAddress = params[0].get_str();
|
||||||
|
|
||||||
auto address = DecodePaymentAddress(strAddress);
|
KeyIO keyIO(Params());
|
||||||
|
auto address = keyIO.DecodePaymentAddress(strAddress);
|
||||||
if (!IsValidPaymentAddress(address)) {
|
if (!IsValidPaymentAddress(address)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
||||||
}
|
}
|
||||||
|
@ -899,7 +911,7 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
|
||||||
if (!sk) {
|
if (!sk) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
||||||
}
|
}
|
||||||
return EncodeSpendingKey(sk.get());
|
return keyIO.EncodeSpendingKey(sk.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
||||||
|
@ -927,14 +939,15 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
string strAddress = params[0].get_str();
|
string strAddress = params[0].get_str();
|
||||||
|
|
||||||
auto address = DecodePaymentAddress(strAddress);
|
KeyIO keyIO(Params());
|
||||||
|
auto address = keyIO.DecodePaymentAddress(strAddress);
|
||||||
if (!IsValidPaymentAddress(address)) {
|
if (!IsValidPaymentAddress(address)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vk = boost::apply_visitor(GetViewingKeyForPaymentAddress(pwalletMain), address);
|
auto vk = boost::apply_visitor(GetViewingKeyForPaymentAddress(pwalletMain), address);
|
||||||
if (vk) {
|
if (vk) {
|
||||||
return EncodeViewingKey(vk.get());
|
return keyIO.EncodeViewingKey(vk.get());
|
||||||
} else {
|
} else {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr");
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,8 @@ UniValue getnewaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
pwalletMain->SetAddressBook(keyID, strAccount, "receive");
|
pwalletMain->SetAddressBook(keyID, strAccount, "receive");
|
||||||
|
|
||||||
return EncodeDestination(keyID);
|
KeyIO keyIO(Params());
|
||||||
|
return keyIO.EncodeDestination(keyID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,7 +237,8 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
UniValue ret(UniValue::VSTR);
|
UniValue ret(UniValue::VSTR);
|
||||||
|
|
||||||
ret = EncodeDestination(GetAccountAddress(strAccount));
|
KeyIO keyIO(Params());
|
||||||
|
ret = keyIO.EncodeDestination(GetAccountAddress(strAccount));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +274,8 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
CKeyID keyID = vchPubKey.GetID();
|
CKeyID keyID = vchPubKey.GetID();
|
||||||
|
|
||||||
return EncodeDestination(keyID);
|
KeyIO keyIO(Params());
|
||||||
|
return keyIO.EncodeDestination(keyID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -295,7 +298,8 @@ UniValue setaccount(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination dest = keyIO.DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
||||||
}
|
}
|
||||||
|
@ -342,7 +346,8 @@ UniValue getaccount(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination dest = keyIO.DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
||||||
}
|
}
|
||||||
|
@ -381,13 +386,14 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
string strAccount = AccountFromValue(params[0]);
|
string strAccount = AccountFromValue(params[0]);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Find all addresses that have the given account
|
// Find all addresses that have the given account
|
||||||
UniValue ret(UniValue::VARR);
|
UniValue ret(UniValue::VARR);
|
||||||
for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
|
for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
|
||||||
const CTxDestination& dest = item.first;
|
const CTxDestination& dest = item.first;
|
||||||
const std::string& strName = item.second.name;
|
const std::string& strName = item.second.name;
|
||||||
if (strName == strAccount) {
|
if (strName == strAccount) {
|
||||||
ret.push_back(EncodeDestination(dest));
|
ret.push_back(keyIO.EncodeDestination(dest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -455,7 +461,8 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination dest = keyIO.DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
||||||
}
|
}
|
||||||
|
@ -513,6 +520,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue jsonGroupings(UniValue::VARR);
|
UniValue jsonGroupings(UniValue::VARR);
|
||||||
std::map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
|
std::map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
|
||||||
for (const std::set<CTxDestination>& grouping : pwalletMain->GetAddressGroupings()) {
|
for (const std::set<CTxDestination>& grouping : pwalletMain->GetAddressGroupings()) {
|
||||||
|
@ -520,7 +528,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
|
||||||
for (const CTxDestination& address : grouping)
|
for (const CTxDestination& address : grouping)
|
||||||
{
|
{
|
||||||
UniValue addressInfo(UniValue::VARR);
|
UniValue addressInfo(UniValue::VARR);
|
||||||
addressInfo.push_back(EncodeDestination(address));
|
addressInfo.push_back(keyIO.EncodeDestination(address));
|
||||||
addressInfo.push_back(ValueFromAmount(balances[address]));
|
addressInfo.push_back(ValueFromAmount(balances[address]));
|
||||||
{
|
{
|
||||||
if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) {
|
if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) {
|
||||||
|
@ -567,7 +575,8 @@ UniValue signmessage(const UniValue& params, bool fHelp)
|
||||||
string strAddress = params[0].get_str();
|
string strAddress = params[0].get_str();
|
||||||
string strMessage = params[1].get_str();
|
string strMessage = params[1].get_str();
|
||||||
|
|
||||||
CTxDestination dest = DecodeDestination(strAddress);
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination dest = keyIO.DecodeDestination(strAddress);
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
|
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
|
||||||
}
|
}
|
||||||
|
@ -621,8 +630,9 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Bitcoin address
|
// Bitcoin address
|
||||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
CTxDestination dest = keyIO.DecodeDestination(params[0].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
||||||
}
|
}
|
||||||
|
@ -960,8 +970,9 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
std::string strAccount = AccountFromValue(params[0]);
|
std::string strAccount = AccountFromValue(params[0]);
|
||||||
CTxDestination dest = DecodeDestination(params[1].get_str());
|
CTxDestination dest = keyIO.DecodeDestination(params[1].get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
|
||||||
}
|
}
|
||||||
|
@ -1053,10 +1064,11 @@ UniValue sendmany(const UniValue& params, bool fHelp)
|
||||||
std::set<CTxDestination> destinations;
|
std::set<CTxDestination> destinations;
|
||||||
std::vector<CRecipient> vecSend;
|
std::vector<CRecipient> vecSend;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
CAmount totalAmount = 0;
|
CAmount totalAmount = 0;
|
||||||
std::vector<std::string> keys = sendTo.getKeys();
|
std::vector<std::string> keys = sendTo.getKeys();
|
||||||
for (const std::string& name_ : keys) {
|
for (const std::string& name_ : keys) {
|
||||||
CTxDestination dest = DecodeDestination(name_);
|
CTxDestination dest = keyIO.DecodeDestination(name_);
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1164,8 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp)
|
||||||
pwalletMain->AddCScript(inner);
|
pwalletMain->AddCScript(inner);
|
||||||
|
|
||||||
pwalletMain->SetAddressBook(innerID, strAccount, "send");
|
pwalletMain->SetAddressBook(innerID, strAccount, "send");
|
||||||
return EncodeDestination(innerID);
|
KeyIO keyIO(Params());
|
||||||
|
return keyIO.EncodeDestination(innerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1218,6 +1231,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// Reply
|
// Reply
|
||||||
UniValue ret(UniValue::VARR);
|
UniValue ret(UniValue::VARR);
|
||||||
std::map<std::string, tallyitem> mapAccountTally;
|
std::map<std::string, tallyitem> mapAccountTally;
|
||||||
|
@ -1250,7 +1265,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
if(fIsWatchonly)
|
if(fIsWatchonly)
|
||||||
obj.pushKV("involvesWatchonly", true);
|
obj.pushKV("involvesWatchonly", true);
|
||||||
obj.pushKV("address", EncodeDestination(dest));
|
obj.pushKV("address", keyIO.EncodeDestination(dest));
|
||||||
obj.pushKV("account", strAccount);
|
obj.pushKV("account", strAccount);
|
||||||
obj.pushKV("amount", ValueFromAmount(nAmount));
|
obj.pushKV("amount", ValueFromAmount(nAmount));
|
||||||
obj.pushKV("amountZat", nAmount);
|
obj.pushKV("amountZat", nAmount);
|
||||||
|
@ -1366,7 +1381,8 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
|
||||||
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
|
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
|
||||||
{
|
{
|
||||||
if (IsValidDestination(dest)) {
|
if (IsValidDestination(dest)) {
|
||||||
entry.pushKV("address", EncodeDestination(dest));
|
KeyIO keyIO(Params());
|
||||||
|
entry.pushKV("address", keyIO.EncodeDestination(dest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2440,12 +2456,13 @@ UniValue listunspent(const UniValue& params, bool fHelp)
|
||||||
if (params.size() > 1)
|
if (params.size() > 1)
|
||||||
nMaxDepth = params[1].get_int();
|
nMaxDepth = params[1].get_int();
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
std::set<CTxDestination> destinations;
|
std::set<CTxDestination> destinations;
|
||||||
if (params.size() > 2) {
|
if (params.size() > 2) {
|
||||||
UniValue inputs = params[2].get_array();
|
UniValue inputs = params[2].get_array();
|
||||||
for (size_t idx = 0; idx < inputs.size(); idx++) {
|
for (size_t idx = 0; idx < inputs.size(); idx++) {
|
||||||
const UniValue& input = inputs[idx];
|
const UniValue& input = inputs[idx];
|
||||||
CTxDestination dest = DecodeDestination(input.get_str());
|
CTxDestination dest = keyIO.DecodeDestination(input.get_str());
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + input.get_str());
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + input.get_str());
|
||||||
}
|
}
|
||||||
|
@ -2477,7 +2494,7 @@ UniValue listunspent(const UniValue& params, bool fHelp)
|
||||||
entry.pushKV("generated", out.tx->IsCoinBase());
|
entry.pushKV("generated", out.tx->IsCoinBase());
|
||||||
|
|
||||||
if (fValidAddress) {
|
if (fValidAddress) {
|
||||||
entry.pushKV("address", EncodeDestination(address));
|
entry.pushKV("address", keyIO.EncodeDestination(address));
|
||||||
|
|
||||||
if (pwalletMain->mapAddressBook.count(address))
|
if (pwalletMain->mapAddressBook.count(address))
|
||||||
entry.pushKV("account", pwalletMain->mapAddressBook[address].name);
|
entry.pushKV("account", pwalletMain->mapAddressBook[address].name);
|
||||||
|
@ -2575,6 +2592,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// User has supplied zaddrs to filter on
|
// User has supplied zaddrs to filter on
|
||||||
if (params.size() > 3) {
|
if (params.size() > 3) {
|
||||||
UniValue addresses = params[3].get_array();
|
UniValue addresses = params[3].get_array();
|
||||||
|
@ -2590,7 +2608,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
|
||||||
}
|
}
|
||||||
string address = o.get_str();
|
string address = o.get_str();
|
||||||
auto zaddr = DecodePaymentAddress(address);
|
auto zaddr = keyIO.DecodePaymentAddress(address);
|
||||||
if (!IsValidPaymentAddress(zaddr)) {
|
if (!IsValidPaymentAddress(zaddr)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
|
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
|
||||||
}
|
}
|
||||||
|
@ -2635,7 +2653,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
obj.pushKV("confirmations", entry.confirmations);
|
obj.pushKV("confirmations", entry.confirmations);
|
||||||
bool hasSproutSpendingKey = HaveSpendingKeyForPaymentAddress(pwalletMain)(entry.address);
|
bool hasSproutSpendingKey = HaveSpendingKeyForPaymentAddress(pwalletMain)(entry.address);
|
||||||
obj.pushKV("spendable", hasSproutSpendingKey);
|
obj.pushKV("spendable", hasSproutSpendingKey);
|
||||||
obj.pushKV("address", EncodePaymentAddress(entry.address));
|
obj.pushKV("address", keyIO.EncodePaymentAddress(entry.address));
|
||||||
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value())));
|
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value())));
|
||||||
std::string data(entry.memo.begin(), entry.memo.end());
|
std::string data(entry.memo.begin(), entry.memo.end());
|
||||||
obj.pushKV("memo", HexStr(data));
|
obj.pushKV("memo", HexStr(data));
|
||||||
|
@ -2652,7 +2670,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
obj.pushKV("confirmations", entry.confirmations);
|
obj.pushKV("confirmations", entry.confirmations);
|
||||||
bool hasSaplingSpendingKey = HaveSpendingKeyForPaymentAddress(pwalletMain)(entry.address);
|
bool hasSaplingSpendingKey = HaveSpendingKeyForPaymentAddress(pwalletMain)(entry.address);
|
||||||
obj.pushKV("spendable", hasSaplingSpendingKey);
|
obj.pushKV("spendable", hasSaplingSpendingKey);
|
||||||
obj.pushKV("address", EncodePaymentAddress(entry.address));
|
obj.pushKV("address", keyIO.EncodePaymentAddress(entry.address));
|
||||||
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
|
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
|
||||||
obj.pushKV("memo", HexStr(entry.memo));
|
obj.pushKV("memo", HexStr(entry.memo));
|
||||||
if (hasSaplingSpendingKey) {
|
if (hasSaplingSpendingKey) {
|
||||||
|
@ -2914,7 +2932,8 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
auto spendingkey = DecodeSpendingKey(params[0].get_str());
|
KeyIO keyIO(Params());
|
||||||
|
auto spendingkey = keyIO.DecodeSpendingKey(params[0].get_str());
|
||||||
if (!IsValidSpendingKey(spendingkey)) {
|
if (!IsValidSpendingKey(spendingkey)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||||
}
|
}
|
||||||
|
@ -3037,8 +3056,9 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
|
||||||
std::vector<SproutSpendingKey> keys;
|
std::vector<SproutSpendingKey> keys;
|
||||||
std::vector<uint256> commitments;
|
std::vector<uint256> commitments;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (const string& name_ : inputs.getKeys()) {
|
for (const string& name_ : inputs.getKeys()) {
|
||||||
auto spendingkey = DecodeSpendingKey(inputs[name_].get_str());
|
auto spendingkey = keyIO.DecodeSpendingKey(inputs[name_].get_str());
|
||||||
if (!IsValidSpendingKey(spendingkey)) {
|
if (!IsValidSpendingKey(spendingkey)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||||
}
|
}
|
||||||
|
@ -3086,7 +3106,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const string& name_ : outputs.getKeys()) {
|
for (const string& name_ : outputs.getKeys()) {
|
||||||
auto addrTo = DecodePaymentAddress(name_);
|
auto addrTo = keyIO.DecodePaymentAddress(name_);
|
||||||
if (!IsValidPaymentAddress(addrTo)) {
|
if (!IsValidPaymentAddress(addrTo)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
|
||||||
}
|
}
|
||||||
|
@ -3206,10 +3226,11 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
|
||||||
auto addr = k.address();
|
auto addr = k.address();
|
||||||
auto viewing_key = k.viewing_key();
|
auto viewing_key = k.viewing_key();
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.pushKV("zcaddress", EncodePaymentAddress(addr));
|
result.pushKV("zcaddress", keyIO.EncodePaymentAddress(addr));
|
||||||
result.pushKV("zcsecretkey", EncodeSpendingKey(k));
|
result.pushKV("zcsecretkey", keyIO.EncodeSpendingKey(k));
|
||||||
result.pushKV("zcviewingkey", EncodeViewingKey(viewing_key));
|
result.pushKV("zcviewingkey", keyIO.EncodeViewingKey(viewing_key));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3246,10 +3267,11 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp)
|
||||||
addrType = params[0].get_str();
|
addrType = params[0].get_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (addrType == ADDR_TYPE_SPROUT) {
|
if (addrType == ADDR_TYPE_SPROUT) {
|
||||||
return EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey());
|
return keyIO.EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey());
|
||||||
} else if (addrType == ADDR_TYPE_SAPLING) {
|
} else if (addrType == ADDR_TYPE_SAPLING) {
|
||||||
return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey());
|
return keyIO.EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey());
|
||||||
} else {
|
} else {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type");
|
||||||
}
|
}
|
||||||
|
@ -3284,13 +3306,14 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
|
||||||
fIncludeWatchonly = params[0].get_bool();
|
fIncludeWatchonly = params[0].get_bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue ret(UniValue::VARR);
|
UniValue ret(UniValue::VARR);
|
||||||
{
|
{
|
||||||
std::set<libzcash::SproutPaymentAddress> addresses;
|
std::set<libzcash::SproutPaymentAddress> addresses;
|
||||||
pwalletMain->GetSproutPaymentAddresses(addresses);
|
pwalletMain->GetSproutPaymentAddresses(addresses);
|
||||||
for (auto addr : addresses) {
|
for (auto addr : addresses) {
|
||||||
if (fIncludeWatchonly || HaveSpendingKeyForPaymentAddress(pwalletMain)(addr)) {
|
if (fIncludeWatchonly || HaveSpendingKeyForPaymentAddress(pwalletMain)(addr)) {
|
||||||
ret.push_back(EncodePaymentAddress(addr));
|
ret.push_back(keyIO.EncodePaymentAddress(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3299,7 +3322,7 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
|
||||||
pwalletMain->GetSaplingPaymentAddresses(addresses);
|
pwalletMain->GetSaplingPaymentAddresses(addresses);
|
||||||
for (auto addr : addresses) {
|
for (auto addr : addresses) {
|
||||||
if (fIncludeWatchonly || HaveSpendingKeyForPaymentAddress(pwalletMain)(addr)) {
|
if (fIncludeWatchonly || HaveSpendingKeyForPaymentAddress(pwalletMain)(addr)) {
|
||||||
ret.push_back(EncodePaymentAddress(addr));
|
ret.push_back(keyIO.EncodePaymentAddress(addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3311,8 +3334,9 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign
|
||||||
vector<COutput> vecOutputs;
|
vector<COutput> vecOutputs;
|
||||||
CAmount balance = 0;
|
CAmount balance = 0;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (transparentAddress.length() > 0) {
|
if (transparentAddress.length() > 0) {
|
||||||
CTxDestination taddr = DecodeDestination(transparentAddress);
|
CTxDestination taddr = keyIO.DecodeDestination(transparentAddress);
|
||||||
if (!IsValidDestination(taddr)) {
|
if (!IsValidDestination(taddr)) {
|
||||||
throw std::runtime_error("invalid transparent address");
|
throw std::runtime_error("invalid transparent address");
|
||||||
}
|
}
|
||||||
|
@ -3427,7 +3451,8 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
|
||||||
// Check that the from address is valid.
|
// Check that the from address is valid.
|
||||||
auto fromaddress = params[0].get_str();
|
auto fromaddress = params[0].get_str();
|
||||||
|
|
||||||
auto zaddr = DecodePaymentAddress(fromaddress);
|
KeyIO keyIO(Params());
|
||||||
|
auto zaddr = keyIO.DecodePaymentAddress(fromaddress);
|
||||||
if (!IsValidPaymentAddress(zaddr)) {
|
if (!IsValidPaymentAddress(zaddr)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
|
||||||
}
|
}
|
||||||
|
@ -3530,13 +3555,14 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Check that the from address is valid.
|
// Check that the from address is valid.
|
||||||
auto fromaddress = params[0].get_str();
|
auto fromaddress = params[0].get_str();
|
||||||
bool fromTaddr = false;
|
bool fromTaddr = false;
|
||||||
CTxDestination taddr = DecodeDestination(fromaddress);
|
CTxDestination taddr = keyIO.DecodeDestination(fromaddress);
|
||||||
fromTaddr = IsValidDestination(taddr);
|
fromTaddr = IsValidDestination(taddr);
|
||||||
if (!fromTaddr) {
|
if (!fromTaddr) {
|
||||||
auto res = DecodePaymentAddress(fromaddress);
|
auto res = keyIO.DecodePaymentAddress(fromaddress);
|
||||||
if (!IsValidPaymentAddress(res)) {
|
if (!IsValidPaymentAddress(res)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||||
}
|
}
|
||||||
|
@ -3705,6 +3731,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Sprout spends
|
// Sprout spends
|
||||||
for (size_t i = 0; i < wtx.vJoinSplit.size(); ++i) {
|
for (size_t i = 0; i < wtx.vJoinSplit.size(); ++i) {
|
||||||
for (size_t j = 0; j < wtx.vJoinSplit[i].nullifiers.size(); ++j) {
|
for (size_t j = 0; j < wtx.vJoinSplit[i].nullifiers.size(); ++j) {
|
||||||
|
@ -3729,7 +3756,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
||||||
entry.pushKV("txidPrev", jsop.hash.GetHex());
|
entry.pushKV("txidPrev", jsop.hash.GetHex());
|
||||||
entry.pushKV("jsPrev", (int)jsop.js);
|
entry.pushKV("jsPrev", (int)jsop.js);
|
||||||
entry.pushKV("jsOutputPrev", (int)jsop.n);
|
entry.pushKV("jsOutputPrev", (int)jsop.n);
|
||||||
entry.pushKV("address", EncodePaymentAddress(pa));
|
entry.pushKV("address", keyIO.EncodePaymentAddress(pa));
|
||||||
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
||||||
entry.pushKV("valueZat", notePt.value());
|
entry.pushKV("valueZat", notePt.value());
|
||||||
spends.push_back(entry);
|
spends.push_back(entry);
|
||||||
|
@ -3749,7 +3776,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
||||||
entry.pushKV("type", ADDR_TYPE_SPROUT);
|
entry.pushKV("type", ADDR_TYPE_SPROUT);
|
||||||
entry.pushKV("js", (int)jsop.js);
|
entry.pushKV("js", (int)jsop.js);
|
||||||
entry.pushKV("jsOutput", (int)jsop.n);
|
entry.pushKV("jsOutput", (int)jsop.n);
|
||||||
entry.pushKV("address", EncodePaymentAddress(pa));
|
entry.pushKV("address", keyIO.EncodePaymentAddress(pa));
|
||||||
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
||||||
entry.pushKV("valueZat", notePt.value());
|
entry.pushKV("valueZat", notePt.value());
|
||||||
addMemo(entry, memo);
|
addMemo(entry, memo);
|
||||||
|
@ -3792,7 +3819,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
||||||
entry.pushKV("spend", (int)i);
|
entry.pushKV("spend", (int)i);
|
||||||
entry.pushKV("txidPrev", op.hash.GetHex());
|
entry.pushKV("txidPrev", op.hash.GetHex());
|
||||||
entry.pushKV("outputPrev", (int)op.n);
|
entry.pushKV("outputPrev", (int)op.n);
|
||||||
entry.pushKV("address", EncodePaymentAddress(pa));
|
entry.pushKV("address", keyIO.EncodePaymentAddress(pa));
|
||||||
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
||||||
entry.pushKV("valueZat", notePt.value());
|
entry.pushKV("valueZat", notePt.value());
|
||||||
spends.push_back(entry);
|
spends.push_back(entry);
|
||||||
|
@ -3831,7 +3858,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
||||||
entry.pushKV("type", ADDR_TYPE_SAPLING);
|
entry.pushKV("type", ADDR_TYPE_SAPLING);
|
||||||
entry.pushKV("output", (int)op.n);
|
entry.pushKV("output", (int)op.n);
|
||||||
entry.pushKV("outgoing", isOutgoing);
|
entry.pushKV("outgoing", isOutgoing);
|
||||||
entry.pushKV("address", EncodePaymentAddress(pa));
|
entry.pushKV("address", keyIO.EncodePaymentAddress(pa));
|
||||||
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
entry.pushKV("value", ValueFromAmount(notePt.value()));
|
||||||
entry.pushKV("valueZat", notePt.value());
|
entry.pushKV("valueZat", notePt.value());
|
||||||
addMemo(entry, memo);
|
addMemo(entry, memo);
|
||||||
|
@ -3997,10 +4024,11 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
||||||
auto fromaddress = params[0].get_str();
|
auto fromaddress = params[0].get_str();
|
||||||
bool fromTaddr = false;
|
bool fromTaddr = false;
|
||||||
bool fromSapling = false;
|
bool fromSapling = false;
|
||||||
CTxDestination taddr = DecodeDestination(fromaddress);
|
KeyIO keyIO(Params());
|
||||||
|
CTxDestination taddr = keyIO.DecodeDestination(fromaddress);
|
||||||
fromTaddr = IsValidDestination(taddr);
|
fromTaddr = IsValidDestination(taddr);
|
||||||
if (!fromTaddr) {
|
if (!fromTaddr) {
|
||||||
auto res = DecodePaymentAddress(fromaddress);
|
auto res = keyIO.DecodePaymentAddress(fromaddress);
|
||||||
if (!IsValidPaymentAddress(res)) {
|
if (!IsValidPaymentAddress(res)) {
|
||||||
// invalid
|
// invalid
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||||
|
@ -4049,9 +4077,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
string address = find_value(o, "address").get_str();
|
string address = find_value(o, "address").get_str();
|
||||||
bool isZaddr = false;
|
bool isZaddr = false;
|
||||||
CTxDestination taddr = DecodeDestination(address);
|
CTxDestination taddr = keyIO.DecodeDestination(address);
|
||||||
if (!IsValidDestination(taddr)) {
|
if (!IsValidDestination(taddr)) {
|
||||||
auto res = DecodePaymentAddress(address);
|
auto res = keyIO.DecodePaymentAddress(address);
|
||||||
if (IsValidPaymentAddress(res)) {
|
if (IsValidPaymentAddress(res)) {
|
||||||
isZaddr = true;
|
isZaddr = true;
|
||||||
|
|
||||||
|
@ -4153,7 +4181,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
||||||
size_t txsize = 0;
|
size_t txsize = 0;
|
||||||
for (int i = 0; i < zaddrRecipients.size(); i++) {
|
for (int i = 0; i < zaddrRecipients.size(); i++) {
|
||||||
auto address = zaddrRecipients[i].address;
|
auto address = zaddrRecipients[i].address;
|
||||||
auto res = DecodePaymentAddress(address);
|
auto res = keyIO.DecodePaymentAddress(address);
|
||||||
bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
||||||
if (toSapling) {
|
if (toSapling) {
|
||||||
mtx.vShieldedOutput.push_back(OutputDescription());
|
mtx.vShieldedOutput.push_back(OutputDescription());
|
||||||
|
@ -4302,7 +4330,8 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) {
|
||||||
// parameter is not set and no default address has yet been generated.
|
// parameter is not set and no default address has yet been generated.
|
||||||
// Note: The following function may return the default address even if it has not been added to the wallet
|
// Note: The following function may return the default address even if it has not been added to the wallet
|
||||||
auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC());
|
auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC());
|
||||||
migrationStatus.pushKV("destination_address", EncodePaymentAddress(destinationAddress));
|
KeyIO keyIO(Params());
|
||||||
|
migrationStatus.pushKV("destination_address", keyIO.EncodePaymentAddress(destinationAddress));
|
||||||
// The values of "unmigrated_amount" and "migrated_amount" MUST take into
|
// The values of "unmigrated_amount" and "migrated_amount" MUST take into
|
||||||
// account failed transactions, that were not mined within their expiration
|
// account failed transactions, that were not mined within their expiration
|
||||||
// height.
|
// height.
|
||||||
|
@ -4431,9 +4460,10 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
// Validate the from address
|
// Validate the from address
|
||||||
auto fromaddress = params[0].get_str();
|
auto fromaddress = params[0].get_str();
|
||||||
bool isFromWildcard = fromaddress == "*";
|
bool isFromWildcard = fromaddress == "*";
|
||||||
|
KeyIO keyIO(Params());
|
||||||
CTxDestination taddr;
|
CTxDestination taddr;
|
||||||
if (!isFromWildcard) {
|
if (!isFromWildcard) {
|
||||||
taddr = DecodeDestination(fromaddress);
|
taddr = keyIO.DecodeDestination(fromaddress);
|
||||||
if (!IsValidDestination(taddr)) {
|
if (!IsValidDestination(taddr)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
|
||||||
}
|
}
|
||||||
|
@ -4441,7 +4471,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
// Validate the destination address
|
// Validate the destination address
|
||||||
auto destaddress = params[1].get_str();
|
auto destaddress = params[1].get_str();
|
||||||
if (!IsValidPaymentAddressString(destaddress)) {
|
if (!keyIO.IsValidPaymentAddressString(destaddress)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
|
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4449,7 +4479,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY);
|
const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY);
|
||||||
|
|
||||||
if (canopyActive) {
|
if (canopyActive) {
|
||||||
auto decodeAddr = DecodePaymentAddress(destaddress);
|
auto decodeAddr = keyIO.DecodePaymentAddress(destaddress);
|
||||||
bool isToSproutZaddr = (boost::get<libzcash::SproutPaymentAddress>(&decodeAddr) != nullptr);
|
bool isToSproutZaddr = (boost::get<libzcash::SproutPaymentAddress>(&decodeAddr) != nullptr);
|
||||||
|
|
||||||
if (isToSproutZaddr) {
|
if (isToSproutZaddr) {
|
||||||
|
@ -4678,6 +4708,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
bool isFromNonSprout = false;
|
bool isFromNonSprout = false;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Sources
|
// Sources
|
||||||
for (const UniValue& o : addresses.getValues()) {
|
for (const UniValue& o : addresses.getValues()) {
|
||||||
if (!o.isStr())
|
if (!o.isStr())
|
||||||
|
@ -4694,12 +4725,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||||
useAnySapling = true;
|
useAnySapling = true;
|
||||||
isFromNonSprout = true;
|
isFromNonSprout = true;
|
||||||
} else {
|
} else {
|
||||||
CTxDestination taddr = DecodeDestination(address);
|
CTxDestination taddr = keyIO.DecodeDestination(address);
|
||||||
if (IsValidDestination(taddr)) {
|
if (IsValidDestination(taddr)) {
|
||||||
taddrs.insert(taddr);
|
taddrs.insert(taddr);
|
||||||
isFromNonSprout = true;
|
isFromNonSprout = true;
|
||||||
} else {
|
} else {
|
||||||
auto zaddr = DecodePaymentAddress(address);
|
auto zaddr = keyIO.DecodePaymentAddress(address);
|
||||||
if (IsValidPaymentAddress(zaddr)) {
|
if (IsValidPaymentAddress(zaddr)) {
|
||||||
zaddrs.insert(zaddr);
|
zaddrs.insert(zaddr);
|
||||||
if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
|
if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
|
||||||
|
@ -4732,9 +4763,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||||
auto destaddress = params[1].get_str();
|
auto destaddress = params[1].get_str();
|
||||||
bool isToSproutZaddr = false;
|
bool isToSproutZaddr = false;
|
||||||
bool isToSaplingZaddr = false;
|
bool isToSaplingZaddr = false;
|
||||||
CTxDestination taddr = DecodeDestination(destaddress);
|
CTxDestination taddr = keyIO.DecodeDestination(destaddress);
|
||||||
if (!IsValidDestination(taddr)) {
|
if (!IsValidDestination(taddr)) {
|
||||||
auto decodeAddr = DecodePaymentAddress(destaddress);
|
auto decodeAddr = keyIO.DecodePaymentAddress(destaddress);
|
||||||
if (IsValidPaymentAddress(decodeAddr)) {
|
if (IsValidPaymentAddress(decodeAddr)) {
|
||||||
if (boost::get<libzcash::SaplingPaymentAddress>(&decodeAddr) != nullptr) {
|
if (boost::get<libzcash::SaplingPaymentAddress>(&decodeAddr) != nullptr) {
|
||||||
isToSaplingZaddr = true;
|
isToSaplingZaddr = true;
|
||||||
|
|
|
@ -68,18 +68,19 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
|
||||||
// new, compressed:
|
// new, compressed:
|
||||||
const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
|
const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
UniValue v;
|
UniValue v;
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
|
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
|
||||||
address = DecodeDestination(v.get_str());
|
address = keyIO.DecodeDestination(v.get_str());
|
||||||
BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address));
|
BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address));
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
|
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
|
||||||
address = DecodeDestination(v.get_str());
|
address = keyIO.DecodeDestination(v.get_str());
|
||||||
BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address));
|
BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address));
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
|
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
|
||||||
address = DecodeDestination(v.get_str());
|
address = keyIO.DecodeDestination(v.get_str());
|
||||||
BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address));
|
BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address));
|
||||||
|
|
||||||
BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
|
BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
|
||||||
|
@ -122,9 +123,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||||
/*********************************
|
/*********************************
|
||||||
* setaccount
|
* setaccount
|
||||||
*********************************/
|
*********************************/
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("setaccount " + EncodeDestination(setaccountDemoAddress) + " \"\""));
|
KeyIO keyIO(Params());
|
||||||
|
BOOST_CHECK_NO_THROW(CallRPC("setaccount " + keyIO.EncodeDestination(setaccountDemoAddress) + " \"\""));
|
||||||
/* Accounts are disabled */
|
/* Accounts are disabled */
|
||||||
BOOST_CHECK_THROW(CallRPC("setaccount " + EncodeDestination(setaccountDemoAddress) + " nullaccount"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("setaccount " + keyIO.EncodeDestination(setaccountDemoAddress) + " nullaccount"), runtime_error);
|
||||||
/* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV is not owned by the test wallet. */
|
/* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV is not owned by the test wallet. */
|
||||||
BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV nullaccount"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV nullaccount"), runtime_error);
|
||||||
BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
|
||||||
|
@ -136,7 +138,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||||
* getbalance
|
* getbalance
|
||||||
*********************************/
|
*********************************/
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
|
BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
|
||||||
BOOST_CHECK_THROW(CallRPC("getbalance " + EncodeDestination(demoAddress)), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("getbalance " + keyIO.EncodeDestination(demoAddress)), runtime_error);
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* listunspent
|
* listunspent
|
||||||
|
@ -178,10 +180,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||||
* listtransactions
|
* listtransactions
|
||||||
*********************************/
|
*********************************/
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
|
BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress)));
|
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress)));
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " 20"));
|
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " 20"));
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " 20 0"));
|
BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " 20 0"));
|
||||||
BOOST_CHECK_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " not_int"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " not_int"), runtime_error);
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* listlockunspent
|
* listlockunspent
|
||||||
|
@ -218,33 +220,33 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||||
/* Accounts are deprecated */
|
/* Accounts are deprecated */
|
||||||
BOOST_CHECK_THROW(CallRPC("getaccountaddress accountThatDoesntExists"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("getaccountaddress accountThatDoesntExists"), runtime_error);
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
|
||||||
BOOST_CHECK(DecodeDestination(retValue.get_str()) == demoAddress);
|
BOOST_CHECK(keyIO.DecodeDestination(retValue.get_str()) == demoAddress);
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* getaccount
|
* getaccount
|
||||||
*********************************/
|
*********************************/
|
||||||
BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
|
||||||
BOOST_CHECK_NO_THROW(CallRPC("getaccount " + EncodeDestination(demoAddress)));
|
BOOST_CHECK_NO_THROW(CallRPC("getaccount " + keyIO.EncodeDestination(demoAddress)));
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* signmessage + verifymessage
|
* signmessage + verifymessage
|
||||||
*********************************/
|
*********************************/
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + EncodeDestination(demoAddress) + " mymessage"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + keyIO.EncodeDestination(demoAddress) + " mymessage"));
|
||||||
BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
|
||||||
/* Should throw error because this address is not loaded in the wallet */
|
/* Should throw error because this address is not loaded in the wallet */
|
||||||
BOOST_CHECK_THROW(CallRPC("signmessage t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe mymessage"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("signmessage t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe mymessage"), runtime_error);
|
||||||
|
|
||||||
/* missing arguments */
|
/* missing arguments */
|
||||||
BOOST_CHECK_THROW(CallRPC("verifymessage " + EncodeDestination(demoAddress)), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress)), runtime_error);
|
||||||
BOOST_CHECK_THROW(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str()), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str()), runtime_error);
|
||||||
/* Illegal address */
|
/* Illegal address */
|
||||||
BOOST_CHECK_THROW(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg " + retValue.get_str() + " mymessage"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg " + retValue.get_str() + " mymessage"), runtime_error);
|
||||||
/* wrong address */
|
/* wrong address */
|
||||||
BOOST_CHECK(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV " + retValue.get_str() + " mymessage").get_bool() == false);
|
BOOST_CHECK(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV " + retValue.get_str() + " mymessage").get_bool() == false);
|
||||||
/* Correct address and signature but wrong message */
|
/* Correct address and signature but wrong message */
|
||||||
BOOST_CHECK(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
|
BOOST_CHECK(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
|
||||||
/* Correct address, message and signature*/
|
/* Correct address, message and signature*/
|
||||||
BOOST_CHECK(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str() + " mymessage").get_bool() == true);
|
BOOST_CHECK(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str() + " mymessage").get_bool() == true);
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* getaddressesbyaccount
|
* getaddressesbyaccount
|
||||||
|
@ -255,7 +257,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||||
BOOST_CHECK_EQUAL(4, arr.size());
|
BOOST_CHECK_EQUAL(4, arr.size());
|
||||||
bool notFound = true;
|
bool notFound = true;
|
||||||
for (auto a : arr.getValues()) {
|
for (auto a : arr.getValues()) {
|
||||||
notFound &= DecodeDestination(a.get_str()) != demoAddress;
|
notFound &= keyIO.DecodeDestination(a.get_str()) != demoAddress;
|
||||||
}
|
}
|
||||||
BOOST_CHECK(!notFound);
|
BOOST_CHECK(!notFound);
|
||||||
|
|
||||||
|
@ -275,36 +277,68 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||||
UniValue obj = retValue.get_obj();
|
UniValue obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 10.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 10.0);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 2.5);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 2.5);
|
||||||
|
BOOST_CHECK(!obj.exists("fundingstreams"));
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 653599")); // Blossom activation - 1
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 653599")); // Blossom activation - 1
|
||||||
obj = retValue.get_obj();
|
obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 10.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 10.0);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 2.5);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 2.5);
|
||||||
|
BOOST_CHECK(!obj.exists("fundingstreams"));
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 653600")); // Blossom activation
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 653600")); // Blossom activation
|
||||||
obj = retValue.get_obj();
|
obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 5.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 5.0);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 1.25);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 1.25);
|
||||||
|
BOOST_CHECK(!obj.exists("fundingstreams"));
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 1046399"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 1046399"));
|
||||||
obj = retValue.get_obj();
|
obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 5.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 5.0);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 1.25);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 1.25);
|
||||||
|
BOOST_CHECK(!obj.exists("fundingstreams"));
|
||||||
|
|
||||||
|
auto check_funding_streams = [](UniValue obj, std::vector<std::string> recipients, std::vector<double> amounts) {
|
||||||
|
size_t n = recipients.size();
|
||||||
|
BOOST_REQUIRE_EQUAL(amounts.size(), n);
|
||||||
|
UniValue fundingstreams = find_value(obj, "fundingstreams");
|
||||||
|
BOOST_CHECK_EQUAL(fundingstreams.size(), n);
|
||||||
|
if (fundingstreams.size() != n) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
UniValue fsobj = fundingstreams[i];
|
||||||
|
BOOST_CHECK_EQUAL(find_value(fsobj, "recipient").get_str(), recipients[i]);
|
||||||
|
BOOST_CHECK_EQUAL(find_value(fsobj, "specification").get_str(), "https://zips.z.cash/zip-0214");
|
||||||
|
BOOST_CHECK_EQUAL(find_value(fsobj, "value").get_real(), amounts[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool canopyEnabled =
|
||||||
|
Params().GetConsensus().vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
|
||||||
|
|
||||||
// slow start + blossom activation + (pre blossom halving - blossom activation) * 2
|
// slow start + blossom activation + (pre blossom halving - blossom activation) * 2
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 1046400"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 1046400"));
|
||||||
obj = retValue.get_obj();
|
obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 3.125);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), canopyEnabled ? 2.5 : 3.125);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
|
||||||
|
if (canopyEnabled) {
|
||||||
|
check_funding_streams(obj, {"Electric Coin Company", "Zcash Foundation", "Major Grants" },
|
||||||
|
{ 0.21875, 0.15625, 0.25 });
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 2726399"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 2726399"));
|
||||||
obj = retValue.get_obj();
|
obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 3.125);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), canopyEnabled ? 2.5 : 3.125);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
|
||||||
|
if (canopyEnabled) {
|
||||||
|
check_funding_streams(obj, {"Electric Coin Company", "Zcash Foundation", "Major Grants" },
|
||||||
|
{ 0.21875, 0.15625, 0.25 });
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 2726400"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 2726400"));
|
||||||
obj = retValue.get_obj();
|
obj = retValue.get_obj();
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 1.5625);
|
BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 1.5625);
|
||||||
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
|
BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
|
||||||
|
BOOST_CHECK(find_value(obj, "fundingstreams").empty());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getblock
|
* getblock
|
||||||
|
@ -493,8 +527,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
|
||||||
libzcash::SproutSpendingKey key;
|
libzcash::SproutSpendingKey key;
|
||||||
BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, key));
|
BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, key));
|
||||||
|
|
||||||
std::string s1 = EncodePaymentAddress(addr);
|
KeyIO keyIO(Params());
|
||||||
std::string s2 = EncodeSpendingKey(key);
|
std::string s1 = keyIO.EncodePaymentAddress(addr);
|
||||||
|
std::string s2 = keyIO.EncodeSpendingKey(key);
|
||||||
|
|
||||||
// There's no way to really delete a private key so we will read in the
|
// There's no way to really delete a private key so we will read in the
|
||||||
// exported wallet file and search for the spending key and payment address.
|
// exported wallet file and search for the spending key and payment address.
|
||||||
|
@ -534,11 +569,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
|
||||||
// error if too many args
|
// error if too many args
|
||||||
BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// create a random key locally
|
// create a random key locally
|
||||||
auto testSpendingKey = libzcash::SproutSpendingKey::random();
|
auto testSpendingKey = libzcash::SproutSpendingKey::random();
|
||||||
auto testPaymentAddress = testSpendingKey.address();
|
auto testPaymentAddress = testSpendingKey.address();
|
||||||
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
|
std::string testAddr = keyIO.EncodePaymentAddress(testPaymentAddress);
|
||||||
std::string testKey = EncodeSpendingKey(testSpendingKey);
|
std::string testKey = keyIO.EncodeSpendingKey(testSpendingKey);
|
||||||
|
|
||||||
// create test data using the random key
|
// create test data using the random key
|
||||||
std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
|
std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
|
||||||
|
@ -576,7 +612,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
|
||||||
BOOST_CHECK(addrs.size()==1);
|
BOOST_CHECK(addrs.size()==1);
|
||||||
|
|
||||||
// check that we have the spending key for the address
|
// check that we have the spending key for the address
|
||||||
auto address = DecodePaymentAddress(testAddr);
|
auto address = keyIO.DecodePaymentAddress(testAddr);
|
||||||
BOOST_CHECK(IsValidPaymentAddress(address));
|
BOOST_CHECK(IsValidPaymentAddress(address));
|
||||||
BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
|
BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
|
||||||
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
|
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
|
||||||
|
@ -585,7 +621,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
|
||||||
// Verify the spending key is the same as the test data
|
// Verify the spending key is the same as the test data
|
||||||
libzcash::SproutSpendingKey k;
|
libzcash::SproutSpendingKey k;
|
||||||
BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k));
|
BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k));
|
||||||
BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k));
|
BOOST_CHECK_EQUAL(testKey, keyIO.EncodeSpendingKey(k));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -608,8 +644,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||||
BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error);
|
||||||
|
|
||||||
// error if invalid args
|
// error if invalid args
|
||||||
|
KeyIO keyIO(Params());
|
||||||
auto sk = libzcash::SproutSpendingKey::random();
|
auto sk = libzcash::SproutSpendingKey::random();
|
||||||
std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes ";
|
std::string prefix = std::string("z_importkey ") + keyIO.EncodeSpendingKey(sk) + " yes ";
|
||||||
BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error);
|
BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error);
|
||||||
BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip
|
BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip
|
||||||
BOOST_CHECK_THROW(CallRPC(prefix + "2147483648"), runtime_error); // not allowed, > int32 used for nHeight
|
BOOST_CHECK_THROW(CallRPC(prefix + "2147483648"), runtime_error); // not allowed, > int32 used for nHeight
|
||||||
|
@ -630,8 +667,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||||
// create a random Sprout key locally
|
// create a random Sprout key locally
|
||||||
auto testSpendingKey = libzcash::SproutSpendingKey::random();
|
auto testSpendingKey = libzcash::SproutSpendingKey::random();
|
||||||
auto testPaymentAddress = testSpendingKey.address();
|
auto testPaymentAddress = testSpendingKey.address();
|
||||||
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
|
std::string testAddr = keyIO.EncodePaymentAddress(testPaymentAddress);
|
||||||
std::string testKey = EncodeSpendingKey(testSpendingKey);
|
std::string testKey = keyIO.EncodeSpendingKey(testSpendingKey);
|
||||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
||||||
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
||||||
|
@ -639,8 +676,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||||
// create a random Sapling key locally
|
// create a random Sapling key locally
|
||||||
auto testSaplingSpendingKey = m.Derive(i);
|
auto testSaplingSpendingKey = m.Derive(i);
|
||||||
auto testSaplingPaymentAddress = testSaplingSpendingKey.DefaultAddress();
|
auto testSaplingPaymentAddress = testSaplingSpendingKey.DefaultAddress();
|
||||||
std::string testSaplingAddr = EncodePaymentAddress(testSaplingPaymentAddress);
|
std::string testSaplingAddr = keyIO.EncodePaymentAddress(testSaplingPaymentAddress);
|
||||||
std::string testSaplingKey = EncodeSpendingKey(testSaplingSpendingKey);
|
std::string testSaplingKey = keyIO.EncodeSpendingKey(testSaplingSpendingKey);
|
||||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testSaplingKey));
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testSaplingKey));
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testSaplingAddr));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testSaplingAddr));
|
||||||
BOOST_CHECK_EQUAL(retValue.get_str(), testSaplingKey);
|
BOOST_CHECK_EQUAL(retValue.get_str(), testSaplingKey);
|
||||||
|
@ -659,7 +696,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||||
|
|
||||||
// Make new addresses for the set
|
// Make new addresses for the set
|
||||||
for (int i=0; i<n2; i++) {
|
for (int i=0; i<n2; i++) {
|
||||||
myaddrs.insert(EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey()));
|
myaddrs.insert(keyIO.EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify number of addresses stored in wallet is n1+n2
|
// Verify number of addresses stored in wallet is n1+n2
|
||||||
|
@ -706,17 +743,18 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_getnewaddress) {
|
||||||
pwalletMain->GenerateNewSeed();
|
pwalletMain->GenerateNewSeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// No parameter defaults to sapling address
|
// No parameter defaults to sapling address
|
||||||
addr = CallRPC("z_getnewaddress");
|
addr = CallRPC("z_getnewaddress");
|
||||||
CheckHaveAddr<SaplingPaymentAddress>(DecodePaymentAddress(addr.get_str()));
|
CheckHaveAddr<SaplingPaymentAddress>(keyIO.DecodePaymentAddress(addr.get_str()));
|
||||||
|
|
||||||
// Passing 'sapling' should also work
|
// Passing 'sapling' should also work
|
||||||
addr = CallRPC("z_getnewaddress sapling");
|
addr = CallRPC("z_getnewaddress sapling");
|
||||||
CheckHaveAddr<SaplingPaymentAddress>(DecodePaymentAddress(addr.get_str()));
|
CheckHaveAddr<SaplingPaymentAddress>(keyIO.DecodePaymentAddress(addr.get_str()));
|
||||||
|
|
||||||
// Should also support sprout
|
// Should also support sprout
|
||||||
addr = CallRPC("z_getnewaddress sprout");
|
addr = CallRPC("z_getnewaddress sprout");
|
||||||
CheckHaveAddr<SproutPaymentAddress>(DecodePaymentAddress(addr.get_str()));
|
CheckHaveAddr<SproutPaymentAddress>(keyIO.DecodePaymentAddress(addr.get_str()));
|
||||||
|
|
||||||
// Should throw on invalid argument
|
// Should throw on invalid argument
|
||||||
CheckRPCThrows("z_getnewaddress garbage", "Invalid address type");
|
CheckRPCThrows("z_getnewaddress garbage", "Invalid address type");
|
||||||
|
@ -1039,7 +1077,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||||
std::fill(v.begin(),v.end(), 'A');
|
std::fill(v.begin(),v.end(), 'A');
|
||||||
std::string badmemo(v.begin(), v.end());
|
std::string badmemo(v.begin(), v.end());
|
||||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||||
std::string zaddr1 = EncodePaymentAddress(pa);
|
KeyIO keyIO(Params());
|
||||||
|
std::string zaddr1 = keyIO.EncodePaymentAddress(pa);
|
||||||
BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ")
|
BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ")
|
||||||
+ "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error);
|
+ "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error);
|
||||||
|
|
||||||
|
@ -1130,7 +1169,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
||||||
std::string taddr1 = retValue.get_str();
|
std::string taddr1 = retValue.get_str();
|
||||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||||
std::string zaddr1 = EncodePaymentAddress(pa);
|
KeyIO keyIO(Params());
|
||||||
|
std::string zaddr1 = keyIO.EncodePaymentAddress(pa);
|
||||||
|
|
||||||
// there are no utxos to spend
|
// there are no utxos to spend
|
||||||
{
|
{
|
||||||
|
@ -1328,11 +1368,12 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling)
|
||||||
|
|
||||||
UniValue retValue;
|
UniValue retValue;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// add keys manually
|
// add keys manually
|
||||||
auto taddr = pwalletMain->GenerateNewKey().GetID();
|
auto taddr = pwalletMain->GenerateNewKey().GetID();
|
||||||
std::string taddr1 = EncodeDestination(taddr);
|
std::string taddr1 = keyIO.EncodeDestination(taddr);
|
||||||
auto pa = pwalletMain->GenerateNewSaplingZKey();
|
auto pa = pwalletMain->GenerateNewSaplingZKey();
|
||||||
std::string zaddr1 = EncodePaymentAddress(pa);
|
std::string zaddr1 = keyIO.EncodePaymentAddress(pa);
|
||||||
|
|
||||||
auto consensusParams = Params().GetConsensus();
|
auto consensusParams = Params().GetConsensus();
|
||||||
retValue = CallRPC("getblockcount");
|
retValue = CallRPC("getblockcount");
|
||||||
|
@ -1677,8 +1718,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
|
||||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight + 1);
|
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight + 1);
|
||||||
|
|
||||||
// Add keys manually
|
// Add keys manually
|
||||||
|
KeyIO keyIO(Params());
|
||||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||||
std::string zaddr = EncodePaymentAddress(pa);
|
std::string zaddr = keyIO.EncodePaymentAddress(pa);
|
||||||
|
|
||||||
// Insufficient funds
|
// Insufficient funds
|
||||||
{
|
{
|
||||||
|
@ -1885,7 +1927,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals)
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
|
||||||
MergeToAddressRecipient taddr1(retValue.get_str(), "");
|
MergeToAddressRecipient taddr1(retValue.get_str(), "");
|
||||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||||
MergeToAddressRecipient zaddr1(EncodePaymentAddress(pa), "DEADBEEF");
|
KeyIO keyIO(Params());
|
||||||
|
MergeToAddressRecipient zaddr1(keyIO.EncodePaymentAddress(pa), "DEADBEEF");
|
||||||
|
|
||||||
// Insufficient funds
|
// Insufficient funds
|
||||||
{
|
{
|
||||||
|
|
|
@ -465,9 +465,10 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
|
||||||
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
|
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
|
||||||
* that never can be redeemed. However, old wallets may still contain
|
* that never can be redeemed. However, old wallets may still contain
|
||||||
* these. Do not add them to the wallet and warn. */
|
* these. Do not add them to the wallet and warn. */
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
||||||
{
|
{
|
||||||
std::string strAddr = EncodeDestination(CScriptID(redeemScript));
|
std::string strAddr = keyIO.EncodeDestination(CScriptID(redeemScript));
|
||||||
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
|
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
|
||||||
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
|
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
|
||||||
return true;
|
return true;
|
||||||
|
@ -2284,13 +2285,14 @@ std::pair<SproutNotePlaintext, SproutPaymentAddress> CWalletTx::DecryptSproutNot
|
||||||
auto nd = this->mapSproutNoteData.at(jsop);
|
auto nd = this->mapSproutNoteData.at(jsop);
|
||||||
SproutPaymentAddress pa = nd.address;
|
SproutPaymentAddress pa = nd.address;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Get cached decryptor
|
// Get cached decryptor
|
||||||
ZCNoteDecryption decryptor;
|
ZCNoteDecryption decryptor;
|
||||||
if (!pwallet->GetNoteDecryptor(pa, decryptor)) {
|
if (!pwallet->GetNoteDecryptor(pa, decryptor)) {
|
||||||
// Note decryptors are created when the wallet is loaded, so it should always exist
|
// Note decryptors are created when the wallet is loaded, so it should always exist
|
||||||
throw std::runtime_error(strprintf(
|
throw std::runtime_error(strprintf(
|
||||||
"Could not find note decryptor for payment address %s",
|
"Could not find note decryptor for payment address %s",
|
||||||
EncodePaymentAddress(pa)));
|
keyIO.EncodePaymentAddress(pa)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hSig = this->vJoinSplit[jsop.js].h_sig(this->joinSplitPubKey);
|
auto hSig = this->vJoinSplit[jsop.js].h_sig(this->joinSplitPubKey);
|
||||||
|
@ -2307,12 +2309,12 @@ std::pair<SproutNotePlaintext, SproutPaymentAddress> CWalletTx::DecryptSproutNot
|
||||||
// Couldn't decrypt with this spending key
|
// Couldn't decrypt with this spending key
|
||||||
throw std::runtime_error(strprintf(
|
throw std::runtime_error(strprintf(
|
||||||
"Could not decrypt note for payment address %s",
|
"Could not decrypt note for payment address %s",
|
||||||
EncodePaymentAddress(pa)));
|
keyIO.EncodePaymentAddress(pa)));
|
||||||
} catch (const std::exception &exc) {
|
} catch (const std::exception &exc) {
|
||||||
// Unexpected failure
|
// Unexpected failure
|
||||||
throw std::runtime_error(strprintf(
|
throw std::runtime_error(strprintf(
|
||||||
"Error while decrypting note for payment address %s: %s",
|
"Error while decrypting note for payment address %s: %s",
|
||||||
EncodePaymentAddress(pa), exc.what()));
|
keyIO.EncodePaymentAddress(pa), exc.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3968,22 +3970,24 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam
|
||||||
}
|
}
|
||||||
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
|
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
|
||||||
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
return false;
|
return false;
|
||||||
if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(EncodeDestination(address), strPurpose))
|
if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(keyIO.EncodeDestination(address), strPurpose))
|
||||||
return false;
|
return false;
|
||||||
return CWalletDB(strWalletFile).WriteName(EncodeDestination(address), strName);
|
return CWalletDB(strWalletFile).WriteName(keyIO.EncodeDestination(address), strName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::DelAddressBook(const CTxDestination& address)
|
bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||||
{
|
{
|
||||||
|
KeyIO keyIO(Params());
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet); // mapAddressBook
|
LOCK(cs_wallet); // mapAddressBook
|
||||||
|
|
||||||
if(fFileBacked)
|
if(fFileBacked)
|
||||||
{
|
{
|
||||||
// Delete destdata tuples associated with address
|
// Delete destdata tuples associated with address
|
||||||
std::string strAddress = EncodeDestination(address);
|
std::string strAddress = keyIO.EncodeDestination(address);
|
||||||
BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
|
BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
|
||||||
{
|
{
|
||||||
CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
|
CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
|
||||||
|
@ -3996,8 +4000,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||||
|
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
return false;
|
return false;
|
||||||
CWalletDB(strWalletFile).ErasePurpose(EncodeDestination(address));
|
CWalletDB(strWalletFile).ErasePurpose(keyIO.EncodeDestination(address));
|
||||||
return CWalletDB(strWalletFile).EraseName(EncodeDestination(address));
|
return CWalletDB(strWalletFile).EraseName(keyIO.EncodeDestination(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
||||||
|
@ -4571,7 +4575,8 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
|
||||||
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
return true;
|
return true;
|
||||||
return CWalletDB(strWalletFile).WriteDestData(EncodeDestination(dest), key, value);
|
KeyIO keyIO(Params());
|
||||||
|
return CWalletDB(strWalletFile).WriteDestData(keyIO.EncodeDestination(dest), key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
|
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
|
||||||
|
@ -4580,7 +4585,8 @@ bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
|
||||||
return false;
|
return false;
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
return true;
|
return true;
|
||||||
return CWalletDB(strWalletFile).EraseDestData(EncodeDestination(dest), key);
|
KeyIO keyIO(Params());
|
||||||
|
return CWalletDB(strWalletFile).EraseDestData(keyIO.EncodeDestination(dest), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
|
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
|
||||||
|
@ -4849,10 +4855,11 @@ bool CWallet::ParameterInteraction()
|
||||||
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
|
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
|
||||||
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
|
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
// Check Sapling migration address if set and is a valid Sapling address
|
// Check Sapling migration address if set and is a valid Sapling address
|
||||||
if (mapArgs.count("-migrationdestaddress")) {
|
if (mapArgs.count("-migrationdestaddress")) {
|
||||||
std::string migrationDestAddress = mapArgs["-migrationdestaddress"];
|
std::string migrationDestAddress = mapArgs["-migrationdestaddress"];
|
||||||
libzcash::PaymentAddress address = DecodePaymentAddress(migrationDestAddress);
|
libzcash::PaymentAddress address = keyIO.DecodePaymentAddress(migrationDestAddress);
|
||||||
if (boost::get<libzcash::SaplingPaymentAddress>(&address) == nullptr) {
|
if (boost::get<libzcash::SaplingPaymentAddress>(&address) == nullptr) {
|
||||||
return UIError(_("-migrationdestaddress must be a valid Sapling address."));
|
return UIError(_("-migrationdestaddress must be a valid Sapling address."));
|
||||||
}
|
}
|
||||||
|
@ -4964,8 +4971,9 @@ void CWallet::GetFilteredNotes(
|
||||||
{
|
{
|
||||||
std::set<PaymentAddress> filterAddresses;
|
std::set<PaymentAddress> filterAddresses;
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (address.length() > 0) {
|
if (address.length() > 0) {
|
||||||
filterAddresses.insert(DecodePaymentAddress(address));
|
filterAddresses.insert(keyIO.DecodePaymentAddress(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey);
|
GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey);
|
||||||
|
@ -4988,6 +4996,7 @@ void CWallet::GetFilteredNotes(
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, cs_wallet);
|
LOCK2(cs_main, cs_wallet);
|
||||||
|
|
||||||
|
KeyIO keyIO(Params());
|
||||||
for (auto & p : mapWallet) {
|
for (auto & p : mapWallet) {
|
||||||
CWalletTx wtx = p.second;
|
CWalletTx wtx = p.second;
|
||||||
|
|
||||||
|
@ -5035,7 +5044,7 @@ void CWallet::GetFilteredNotes(
|
||||||
ZCNoteDecryption decryptor;
|
ZCNoteDecryption decryptor;
|
||||||
if (!GetNoteDecryptor(pa, decryptor)) {
|
if (!GetNoteDecryptor(pa, decryptor)) {
|
||||||
// Note decryptors are created when the wallet is loaded, so it should always exist
|
// Note decryptors are created when the wallet is loaded, so it should always exist
|
||||||
throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa)));
|
throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", keyIO.EncodePaymentAddress(pa)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine amount of funds in the note
|
// determine amount of funds in the note
|
||||||
|
@ -5053,10 +5062,10 @@ void CWallet::GetFilteredNotes(
|
||||||
|
|
||||||
} catch (const note_decryption_failed &err) {
|
} catch (const note_decryption_failed &err) {
|
||||||
// Couldn't decrypt with this spending key
|
// Couldn't decrypt with this spending key
|
||||||
throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa)));
|
throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", keyIO.EncodePaymentAddress(pa)));
|
||||||
} catch (const std::exception &exc) {
|
} catch (const std::exception &exc) {
|
||||||
// Unexpected failure
|
// Unexpected failure
|
||||||
throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what()));
|
throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", keyIO.EncodePaymentAddress(pa), exc.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5243,8 +5252,9 @@ KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::InvalidEncoding&
|
||||||
|
|
||||||
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const {
|
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const {
|
||||||
auto addr = sk.address();
|
auto addr = sk.address();
|
||||||
|
KeyIO keyIO(Params());
|
||||||
if (log){
|
if (log){
|
||||||
LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
|
LogPrint("zrpc", "Importing zaddr %s...\n", keyIO.EncodePaymentAddress(addr));
|
||||||
}
|
}
|
||||||
if (m_wallet->HaveSproutSpendingKey(addr)) {
|
if (m_wallet->HaveSproutSpendingKey(addr)) {
|
||||||
return KeyAlreadyExists;
|
return KeyAlreadyExists;
|
||||||
|
@ -5259,9 +5269,10 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKe
|
||||||
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
|
KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
|
||||||
auto extfvk = sk.ToXFVK();
|
auto extfvk = sk.ToXFVK();
|
||||||
auto ivk = extfvk.fvk.in_viewing_key();
|
auto ivk = extfvk.fvk.in_viewing_key();
|
||||||
|
KeyIO keyIO(Params());
|
||||||
{
|
{
|
||||||
if (log){
|
if (log){
|
||||||
LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(sk.DefaultAddress()));
|
LogPrint("zrpc", "Importing zaddr %s...\n", keyIO.EncodePaymentAddress(sk.DefaultAddress()));
|
||||||
}
|
}
|
||||||
// Don't throw error in case a key is already there
|
// Don't throw error in case a key is already there
|
||||||
if (m_wallet->HaveSaplingSpendingKey(extfvk)) {
|
if (m_wallet->HaveSaplingSpendingKey(extfvk)) {
|
||||||
|
|
|
@ -458,6 +458,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
CWalletScanState &wss, string& strType, string& strErr)
|
CWalletScanState &wss, string& strType, string& strErr)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
KeyIO keyIO(Params());
|
||||||
|
|
||||||
// Unserialize
|
// Unserialize
|
||||||
// Taking advantage of the fact that pair serialization
|
// Taking advantage of the fact that pair serialization
|
||||||
// is just the two items serialized one after the other
|
// is just the two items serialized one after the other
|
||||||
|
@ -466,13 +468,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
{
|
{
|
||||||
string strAddress;
|
string strAddress;
|
||||||
ssKey >> strAddress;
|
ssKey >> strAddress;
|
||||||
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
|
ssValue >> pwallet->mapAddressBook[keyIO.DecodeDestination(strAddress)].name;
|
||||||
}
|
}
|
||||||
else if (strType == "purpose")
|
else if (strType == "purpose")
|
||||||
{
|
{
|
||||||
string strAddress;
|
string strAddress;
|
||||||
ssKey >> strAddress;
|
ssKey >> strAddress;
|
||||||
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
|
ssValue >> pwallet->mapAddressBook[keyIO.DecodeDestination(strAddress)].purpose;
|
||||||
}
|
}
|
||||||
else if (strType == "tx")
|
else if (strType == "tx")
|
||||||
{
|
{
|
||||||
|
@ -829,7 +831,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
ssKey >> strAddress;
|
ssKey >> strAddress;
|
||||||
ssKey >> strKey;
|
ssKey >> strKey;
|
||||||
ssValue >> strValue;
|
ssValue >> strValue;
|
||||||
if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue))
|
if (!pwallet->LoadDestData(keyIO.DecodeDestination(strAddress), strKey, strValue))
|
||||||
{
|
{
|
||||||
strErr = "Error reading wallet database: LoadDestData failed";
|
strErr = "Error reading wallet database: LoadDestData failed";
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -68,6 +68,7 @@ enum class Zip212Enabled {
|
||||||
BeforeZip212,
|
BeforeZip212,
|
||||||
AfterZip212
|
AfterZip212
|
||||||
};
|
};
|
||||||
|
|
||||||
class SaplingNote : public BaseNote {
|
class SaplingNote : public BaseNote {
|
||||||
private:
|
private:
|
||||||
uint256 rseed;
|
uint256 rseed;
|
||||||
|
|
Loading…
Reference in New Issue