Auto merge of #3596 - bitcartel:stop_v3_tx_creation_when_sapling, r=bitcartel

For #3359. RPCs return error if Sapling addresses used before Sapling activation.
This commit is contained in:
Homu 2018-10-13 13:20:02 -07:00
commit f358a92ec4
2 changed files with 88 additions and 2 deletions

View File

@ -19,17 +19,57 @@ class WalletSaplingTest(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, [[
'-nuparams=5ba81b19:201', # Overwinter
'-nuparams=76b809bb:201', # Sapling
'-nuparams=76b809bb:203', # Sapling
'-experimentalfeatures', '-zmergetoaddress',
]] * 4)
def run_test(self):
# Sanity-check the test harness
assert_equal(self.nodes[0].getblockcount(), 200)
# Activate Sapling
# Activate Overwinter
self.nodes[2].generate(1)
self.sync_all()
# Verify RPCs disallow Sapling value transfer if Sapling is not active
tmp_taddr = self.nodes[3].getnewaddress()
tmp_zaddr = self.nodes[3].z_getnewaddress('sapling')
try:
recipients = []
recipients.append({"address": tmp_zaddr, "amount": Decimal('20')})
self.nodes[3].z_sendmany(tmp_taddr, recipients, 1, 0)
raise AssertionError("Should have thrown an exception")
except JSONRPCException as e:
assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])
try:
recipients = []
recipients.append({"address": tmp_taddr, "amount": Decimal('20')})
self.nodes[3].z_sendmany(tmp_zaddr, recipients, 1, 0)
raise AssertionError("Should have thrown an exception")
except JSONRPCException as e:
assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])
try:
self.nodes[3].z_shieldcoinbase(tmp_taddr, tmp_zaddr)
raise AssertionError("Should have thrown an exception")
except JSONRPCException as e:
assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])
# Verify z_mergetoaddress RPC does not support Sapling yet
try:
self.nodes[3].z_mergetoaddress([tmp_taddr], tmp_zaddr)
raise AssertionError("Should have thrown an exception")
except JSONRPCException as e:
assert_equal("Invalid parameter, Sapling is not supported yet by z_mergetoadress", e.error['message'])
try:
self.nodes[3].z_mergetoaddress([tmp_zaddr], tmp_taddr)
raise AssertionError("Should have thrown an exception")
except JSONRPCException as e:
assert_equal("Invalid parameter, Sapling is not supported yet by z_mergetoadress", e.error['message'])
# Activate Sapling
self.nodes[2].generate(2)
self.sync_all()
taddr0 = self.nodes[0].getnewaddress()
# Skip over the address containing node 1's coinbase
self.nodes[1].getnewaddress()

View File

@ -3795,6 +3795,13 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
}
}
// If Sapling is not active, do not allow sending from or sending to Sapling addresses.
if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
if (fromSapling || containsSaplingOutput) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
}
}
// As a sanity check, estimate and verify that the size of the transaction will be valid.
// Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
size_t txsize = 0;
@ -3984,6 +3991,19 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
}
// If Sapling is not active, do not allow sending to a Sapling address.
if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
auto res = DecodePaymentAddress(destaddress);
if (IsValidPaymentAddress(res)) {
bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
if (toSapling) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
}
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
}
}
// Prepare to get coinbase utxos
std::vector<ShieldCoinbaseUTXO> inputs;
CAmount shieldedValue = 0;
@ -4184,6 +4204,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
std::set<std::string> setAddress;
// Sources
bool containsSaplingZaddrSource = false;
for (const UniValue& o : addresses.getValues()) {
if (!o.isStr())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
@ -4209,6 +4230,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
if (!(useAny || useAnyNote)) {
zaddrs.insert(zaddr);
}
// Check if z-addr is Sapling
bool isSapling = boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr;
containsSaplingZaddrSource |= isSapling;
} else {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
@ -4225,10 +4249,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
// Validate the destination address
auto destaddress = params[1].get_str();
bool isToZaddr = false;
bool isToSaplingZaddr = false;
CTxDestination taddr = DecodeDestination(destaddress);
if (!IsValidDestination(taddr)) {
if (IsValidPaymentAddressString(destaddress)) {
isToZaddr = true;
// Is this a Sapling address?
auto res = DecodePaymentAddress(destaddress);
if (IsValidPaymentAddress(res)) {
isToSaplingZaddr = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
}
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
}
@ -4282,6 +4315,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
}
// This RPC does not support Sapling yet.
if (isToSaplingZaddr || containsSaplingZaddrSource) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling is not supported yet by z_mergetoadress");
}
// If this RPC does support Sapling...
// If Sapling is not active, do not allow sending from or sending to Sapling addresses.
if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
if (isToSaplingZaddr || containsSaplingZaddrSource) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
}
}
// Prepare to get UTXOs and notes
std::vector<MergeToAddressInputUTXO> utxoInputs;
std::vector<MergeToAddressInputNote> noteInputs;