Remove `zcraw*` RPC methods
This commit is contained in:
parent
ad8bd0d254
commit
37921677e9
|
@ -66,11 +66,3 @@ Stage 2
|
|||
Each feature in the lists below may be enabled by adding `-allowdeprecated=<feature>`
|
||||
to the CLI arguments when starting the node, or by adding an `allowdeprecated=<feature>`
|
||||
line to `zcash.conf`.
|
||||
|
||||
### Disabled in 5.0.0
|
||||
|
||||
The following features are disabled by default, and will be removed in release 5.3.0.
|
||||
|
||||
- `zcrawreceive` - The `zcrawreceive` RPC method is disabled.
|
||||
- `zcrawjoinsplit` - The `zcrawjoinsplit` RPC method is disabled.
|
||||
- `zcrawkeygen` - The `zcrawkeygen` RPC method is disabled.
|
||||
|
|
|
@ -20,3 +20,6 @@ RPC Changes
|
|||
The following previously-deprecated features have been removed:
|
||||
|
||||
- `dumpwallet`
|
||||
- `zcrawreceive`
|
||||
- `zcrawjoinsplit`
|
||||
- `zcrawkeygen`
|
||||
|
|
|
@ -42,9 +42,7 @@ BASE_SCRIPTS= [
|
|||
'wallet_shieldcoinbase_sprout.py',
|
||||
'sprout_sapling_migration.py',
|
||||
'remove_sprout_shielding.py',
|
||||
'zcjoinsplitdoublespend.py',
|
||||
# vv Tests less than 2m vv
|
||||
'zcjoinsplit.py',
|
||||
'mergetoaddress_mixednotes.py',
|
||||
'wallet_shieldcoinbase_sapling.py',
|
||||
'wallet_shieldcoinbase_ua_sapling.py',
|
||||
|
|
|
@ -38,7 +38,7 @@ Options:
|
|||
selected from among {"none", "addrtype", "getnewaddress",
|
||||
"getrawchangeaddress", "legacy_privacy", "wallettxvjoinsplit",
|
||||
"z_getbalance", "z_getnewaddress", "z_gettotalbalance",
|
||||
"z_listaddresses", "zcrawjoinsplit", "zcrawkeygen", "zcrawreceive"}
|
||||
"z_listaddresses"}
|
||||
|
||||
-blocknotify=<cmd>
|
||||
Execute command when the best block changes (%s in cmd is replaced by
|
||||
|
|
|
@ -58,7 +58,6 @@ class WalletDeprecationTest(BitcoinTestFramework):
|
|||
"z_getnewaddress",
|
||||
]
|
||||
DEFAULT_DISABLED = [
|
||||
"zcrawkeygen",
|
||||
]
|
||||
|
||||
# RPC methods that are deprecated but enabled by default should succeed
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Test joinsplit semantics
|
||||
#
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, start_node, \
|
||||
gather_inputs
|
||||
|
||||
|
||||
class JoinSplitTest(BitcoinTestFramework):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.num_nodes = 1
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
self.is_network_split = False
|
||||
self.nodes.append(start_node(0, self.options.tmpdir,
|
||||
["-allowdeprecated=zcrawkeygen", "-allowdeprecated=zcrawjoinsplit", "-allowdeprecated=zcrawreceive"]
|
||||
))
|
||||
|
||||
def run_test(self):
|
||||
zckeypair = self.nodes[0].zcrawkeygen()
|
||||
zcsecretkey = zckeypair["zcsecretkey"]
|
||||
zcaddress = zckeypair["zcaddress"]
|
||||
|
||||
(total_in, inputs) = gather_inputs(self.nodes[0], 40)
|
||||
shield_tx = self.nodes[0].createrawtransaction(inputs, {})
|
||||
joinsplit_result = self.nodes[0].zcrawjoinsplit(shield_tx, {}, {zcaddress:39.99}, 39.99, 0)
|
||||
|
||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
||||
assert_equal(receive_result["exists"], False)
|
||||
|
||||
shield_tx = self.nodes[0].signrawtransaction(joinsplit_result["rawtxn"])
|
||||
self.nodes[0].sendrawtransaction(shield_tx["hex"])
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
# The pure joinsplit we create should be mined in the next block
|
||||
# despite other transactions being in the mempool.
|
||||
addrtest = self.nodes[0].getnewaddress()
|
||||
for xx in range(0,10):
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
for x in range(0,50):
|
||||
self.nodes[0].sendtoaddress(addrtest, 0.01);
|
||||
|
||||
joinsplit_tx = self.nodes[0].createrawtransaction([], {})
|
||||
joinsplit_result = self.nodes[0].zcrawjoinsplit(joinsplit_tx, {receive_result["note"] : zcsecretkey}, {zcaddress: 39.98}, 0, 0.01)
|
||||
|
||||
self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"])
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
print("Done!")
|
||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
JoinSplitTest().main()
|
|
@ -1,186 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Tests a joinsplit double-spend and a subsequent reorg.
|
||||
#
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.util import assert_equal, connect_nodes, \
|
||||
gather_inputs, start_nodes, sync_blocks
|
||||
|
||||
import time
|
||||
|
||||
class JoinSplitTest(BitcoinTestFramework):
|
||||
def setup_network(self):
|
||||
# Start with split network:
|
||||
return super(JoinSplitTest, self).setup_network(True)
|
||||
|
||||
def setup_nodes(self):
|
||||
return start_nodes(self.num_nodes, self.options.tmpdir,
|
||||
extra_args = [["-allowdeprecated=zcrawjoinsplit", "-allowdeprecated=zcrawkeygen", "-allowdeprecated=zcrawreceive"]] * self.num_nodes)
|
||||
|
||||
def txid_in_mempool(self, node, txid):
|
||||
exception_triggered = False
|
||||
|
||||
try:
|
||||
node.getrawtransaction(txid)
|
||||
except JSONRPCException:
|
||||
exception_triggered = True
|
||||
|
||||
return not exception_triggered
|
||||
|
||||
def cannot_joinsplit(self, node, txn):
|
||||
exception_triggered = False
|
||||
|
||||
try:
|
||||
node.sendrawtransaction(txn)
|
||||
except JSONRPCException:
|
||||
exception_triggered = True
|
||||
|
||||
return exception_triggered
|
||||
|
||||
def expect_cannot_joinsplit(self, node, txn):
|
||||
assert_equal(self.cannot_joinsplit(node, txn), True)
|
||||
|
||||
def run_test(self):
|
||||
# All nodes should start with 250 ZEC:
|
||||
starting_balance = 250
|
||||
for i in range(4):
|
||||
assert_equal(self.nodes[i].getbalance(), starting_balance)
|
||||
self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
|
||||
|
||||
# Generate zcaddress keypairs
|
||||
zckeypair = self.nodes[0].zcrawkeygen()
|
||||
zcsecretkey = zckeypair["zcsecretkey"]
|
||||
zcaddress = zckeypair["zcaddress"]
|
||||
|
||||
pool = [0, 1, 2, 3]
|
||||
for i in range(4):
|
||||
(total_in, inputs) = gather_inputs(self.nodes[i], 40)
|
||||
pool[i] = self.nodes[i].createrawtransaction(inputs, {})
|
||||
pool[i] = self.nodes[i].zcrawjoinsplit(pool[i], {}, {zcaddress:39.99}, 39.99, 0)
|
||||
signed = self.nodes[i].signrawtransaction(pool[i]["rawtxn"])
|
||||
|
||||
# send the tx to both halves of the network
|
||||
self.nodes[0].sendrawtransaction(signed["hex"])
|
||||
self.nodes[0].generate(1)
|
||||
self.nodes[2].sendrawtransaction(signed["hex"])
|
||||
self.nodes[2].generate(1)
|
||||
pool[i] = pool[i]["encryptednote1"]
|
||||
|
||||
sync_blocks(self.nodes[0:2])
|
||||
sync_blocks(self.nodes[2:4])
|
||||
|
||||
# Confirm that the protects have taken place
|
||||
for i in range(4):
|
||||
enc_note = pool[i]
|
||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_note)
|
||||
assert_equal(receive_result["exists"], True)
|
||||
pool[i] = receive_result["note"]
|
||||
|
||||
# Extra confirmations
|
||||
receive_result = self.nodes[1].zcrawreceive(zcsecretkey, enc_note)
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
receive_result = self.nodes[2].zcrawreceive(zcsecretkey, enc_note)
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
receive_result = self.nodes[3].zcrawreceive(zcsecretkey, enc_note)
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
blank_tx = self.nodes[0].createrawtransaction([], {})
|
||||
# Create joinsplit {A, B}->{*}
|
||||
joinsplit_AB = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[0] : zcsecretkey, pool[1] : zcsecretkey},
|
||||
{zcaddress:(39.99*2)-0.01},
|
||||
0, 0.01)
|
||||
|
||||
# Create joinsplit {B, C}->{*}
|
||||
joinsplit_BC = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[1] : zcsecretkey, pool[2] : zcsecretkey},
|
||||
{zcaddress:(39.99*2)-0.01},
|
||||
0, 0.01)
|
||||
|
||||
# Create joinsplit {C, D}->{*}
|
||||
joinsplit_CD = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[2] : zcsecretkey, pool[3] : zcsecretkey},
|
||||
{zcaddress:(39.99*2)-0.01},
|
||||
0, 0.01)
|
||||
|
||||
# Create joinsplit {A, D}->{*}
|
||||
joinsplit_AD = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[0] : zcsecretkey, pool[3] : zcsecretkey},
|
||||
{zcaddress:(39.99*2)-0.01},
|
||||
0, 0.01)
|
||||
|
||||
# (a) Node 0 will spend joinsplit AB, then attempt to
|
||||
# double-spend it with BC. It should fail before and
|
||||
# after Node 0 mines blocks.
|
||||
#
|
||||
# (b) Then, Node 2 will spend BC, and mine 5 blocks.
|
||||
# Node 1 connects, and AB will be reorg'd from the chain.
|
||||
# Any attempts to spend AB or CD should fail for
|
||||
# both nodes.
|
||||
#
|
||||
# (c) Then, Node 0 will spend AD, which should work
|
||||
# because the previous spend for A (AB) is considered
|
||||
# invalid due to the reorg.
|
||||
|
||||
# (a)
|
||||
|
||||
AB_txid = self.nodes[0].sendrawtransaction(joinsplit_AB["rawtxn"])
|
||||
|
||||
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
|
||||
|
||||
# Wait until node[1] receives AB before we attempt to double-spend
|
||||
# with BC.
|
||||
print("Waiting for AB_txid...\n")
|
||||
while True:
|
||||
if self.txid_in_mempool(self.nodes[1], AB_txid):
|
||||
break
|
||||
time.sleep(0.2)
|
||||
print("Done!\n")
|
||||
|
||||
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
|
||||
|
||||
# Generate a block
|
||||
self.nodes[0].generate(1)
|
||||
sync_blocks(self.nodes[0:2])
|
||||
|
||||
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
|
||||
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
|
||||
|
||||
# (b)
|
||||
self.nodes[2].sendrawtransaction(joinsplit_BC["rawtxn"])
|
||||
self.nodes[2].generate(5)
|
||||
|
||||
# Connect the two nodes
|
||||
|
||||
connect_nodes(self.nodes[1], 2)
|
||||
sync_blocks(self.nodes)
|
||||
|
||||
# AB and CD should all be impossible to spend for each node.
|
||||
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_AB["rawtxn"])
|
||||
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_CD["rawtxn"])
|
||||
|
||||
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_AB["rawtxn"])
|
||||
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_CD["rawtxn"])
|
||||
|
||||
self.expect_cannot_joinsplit(self.nodes[2], joinsplit_AB["rawtxn"])
|
||||
self.expect_cannot_joinsplit(self.nodes[2], joinsplit_CD["rawtxn"])
|
||||
|
||||
self.expect_cannot_joinsplit(self.nodes[3], joinsplit_AB["rawtxn"])
|
||||
self.expect_cannot_joinsplit(self.nodes[3], joinsplit_CD["rawtxn"])
|
||||
|
||||
# (c)
|
||||
# AD should be possible to send due to the reorg that
|
||||
# tossed out AB.
|
||||
|
||||
self.nodes[0].sendrawtransaction(joinsplit_AD["rawtxn"])
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
sync_blocks(self.nodes)
|
||||
|
||||
if __name__ == '__main__':
|
||||
JoinSplitTest().main()
|
|
@ -20,9 +20,6 @@ bool fEnableZGetBalance = true;
|
|||
bool fEnableZGetTotalBalance = true;
|
||||
bool fEnableZListAddresses = true;
|
||||
bool fEnableLegacyPrivacyStrategy = true;
|
||||
bool fEnableZCRawReceive = true;
|
||||
bool fEnableZCRawJoinSplit = true;
|
||||
bool fEnableZCRawKeygen = true;
|
||||
bool fEnableAddrTypeField = true;
|
||||
bool fEnableWalletTxVJoinSplit = true;
|
||||
#endif
|
||||
|
@ -102,9 +99,6 @@ std::optional<std::string> SetAllowedDeprecatedFeaturesFromCLIArgs() {
|
|||
fEnableZGetBalance = allowdeprecated.count("z_getbalance") > 0;
|
||||
fEnableZGetTotalBalance = allowdeprecated.count("z_gettotalbalance") > 0;
|
||||
fEnableZListAddresses = allowdeprecated.count("z_listaddresses") > 0;
|
||||
fEnableZCRawReceive = allowdeprecated.count("zcrawreceive") > 0;
|
||||
fEnableZCRawJoinSplit = allowdeprecated.count("zcrawjoinsplit") > 0;
|
||||
fEnableZCRawKeygen = allowdeprecated.count("zcrawkeygen") > 0;
|
||||
fEnableAddrTypeField = allowdeprecated.count("addrtype") > 0;
|
||||
fEnableWalletTxVJoinSplit = allowdeprecated.count("wallettxvjoinsplit") > 0;
|
||||
#endif
|
||||
|
|
|
@ -39,9 +39,6 @@ static const std::set<std::string> DEFAULT_ALLOW_DEPRECATED{{
|
|||
}};
|
||||
static const std::set<std::string> DEFAULT_DENY_DEPRECATED{{
|
||||
#ifdef ENABLE_WALLET
|
||||
"zcrawreceive",
|
||||
"zcrawjoinsplit",
|
||||
"zcrawkeygen"
|
||||
#endif
|
||||
}};
|
||||
|
||||
|
@ -54,9 +51,6 @@ extern bool fEnableZGetBalance;
|
|||
extern bool fEnableZGetTotalBalance;
|
||||
extern bool fEnableZListAddresses;
|
||||
extern bool fEnableLegacyPrivacyStrategy;
|
||||
extern bool fEnableZCRawReceive;
|
||||
extern bool fEnableZCRawJoinSplit;
|
||||
extern bool fEnableZCRawKeygen;
|
||||
extern bool fEnableAddrTypeField;
|
||||
extern bool fEnableWalletTxVJoinSplit;
|
||||
#endif
|
||||
|
|
|
@ -104,10 +104,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "getblockhashes", 1},
|
||||
{ "getblockhashes", 2},
|
||||
{ "getblockdeltas", 0},
|
||||
{ "zcrawjoinsplit", 1 },
|
||||
{ "zcrawjoinsplit", 2 },
|
||||
{ "zcrawjoinsplit", 3 },
|
||||
{ "zcrawjoinsplit", 4 },
|
||||
{ "zcbenchmark", 1 },
|
||||
{ "zcbenchmark", 2 },
|
||||
{ "getblocksubsidy", 0},
|
||||
|
|
|
@ -3026,360 +3026,6 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
|
|||
return results;
|
||||
}
|
||||
|
||||
UniValue zc_raw_receive(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (!fEnableZCRawReceive)
|
||||
throw runtime_error(
|
||||
"zcrawreceive is DEPRECATED and will be removed in a future release\n"
|
||||
"\nrestart with `-allowdeprecated=zcrawreceive` if you require backward compatibility.\n"
|
||||
"See https://zcash.github.io/zcash/user/deprecation.html for more information.");
|
||||
|
||||
if (fHelp || params.size() != 2) {
|
||||
throw runtime_error(
|
||||
"zcrawreceive zcsecretkey encryptednote\n"
|
||||
"\n"
|
||||
"DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
|
||||
"are in the blockchain as indicated by the \"exists\" result.\n"
|
||||
"\n"
|
||||
"Output: {\n"
|
||||
" \"amount\": value,\n"
|
||||
" \"note\": noteplaintext,\n"
|
||||
" \"exists\": exists\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
KeyIO keyIO(Params());
|
||||
auto spendingkey = keyIO.DecodeSpendingKey(params[0].get_str());
|
||||
if (!spendingkey.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||
}
|
||||
if (std::get_if<libzcash::SproutSpendingKey>(&spendingkey.value()) == nullptr) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
|
||||
}
|
||||
SproutSpendingKey k = std::get<libzcash::SproutSpendingKey>(spendingkey.value());
|
||||
|
||||
uint256 epk;
|
||||
unsigned char nonce;
|
||||
ZCNoteEncryption::Ciphertext ct;
|
||||
uint256 h_sig;
|
||||
|
||||
{
|
||||
CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ssData >> nonce;
|
||||
ssData >> epk;
|
||||
ssData >> ct;
|
||||
ssData >> h_sig;
|
||||
} catch(const std::exception &) {
|
||||
throw runtime_error(
|
||||
"encrypted_note could not be decoded"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ZCNoteDecryption decryptor(k.receiving_key());
|
||||
|
||||
SproutNotePlaintext npt = SproutNotePlaintext::decrypt(
|
||||
decryptor,
|
||||
ct,
|
||||
epk,
|
||||
h_sig,
|
||||
nonce
|
||||
);
|
||||
SproutPaymentAddress payment_addr = k.address();
|
||||
SproutNote decrypted_note = npt.note(payment_addr);
|
||||
|
||||
assert(pwalletMain != NULL);
|
||||
std::vector<std::optional<SproutWitness>> witnesses;
|
||||
uint256 anchor;
|
||||
uint256 commitment = decrypted_note.cm();
|
||||
pwalletMain->WitnessNoteCommitment(
|
||||
{commitment},
|
||||
witnesses,
|
||||
anchor
|
||||
);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << npt;
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("amount", ValueFromAmount(decrypted_note.value()));
|
||||
result.pushKV("note", HexStr(ss.begin(), ss.end()));
|
||||
result.pushKV("exists", (bool) witnesses[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (!fEnableZCRawJoinSplit)
|
||||
throw runtime_error(
|
||||
"zcrawjoinsplit is DEPRECATED and will be removed in a future release\n"
|
||||
"\nrestart with `-allowdeprecated=zcrawjoinsplit` if you require backward compatibility.\n"
|
||||
"See https://zcash.github.io/zcash/user/deprecation.html for more information.");
|
||||
|
||||
if (fHelp || params.size() != 5) {
|
||||
throw runtime_error(
|
||||
"zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
|
||||
" inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
|
||||
" outputs: a JSON object mapping {zcaddr: value, ...}\n"
|
||||
"\n"
|
||||
"DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
|
||||
"Outputs are confidential between sender/receiver. The vpub_old and\n"
|
||||
"vpub_new values are globally public and move transparent value into\n"
|
||||
"or out of the confidential value store, respectively.\n"
|
||||
"\n"
|
||||
"Note: The caller is responsible for delivering the output enc1 and\n"
|
||||
"enc2 to the appropriate recipients, as well as signing rawtxout and\n"
|
||||
"ensuring it is mined. (A future RPC call will deliver the confidential\n"
|
||||
"payments in-band on the blockchain.)\n"
|
||||
"\n"
|
||||
"Output: {\n"
|
||||
" \"encryptednote1\": enc1,\n"
|
||||
" \"encryptednote2\": enc2,\n"
|
||||
" \"rawtxn\": rawtxout\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
CTransaction tx;
|
||||
if (!DecodeHexTx(tx, params[0].get_str()))
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
|
||||
if (tx.nVersion >= ZIP225_TX_VERSION) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "v5+ transactions do not support Sprout");
|
||||
}
|
||||
|
||||
UniValue inputs = params[1].get_obj();
|
||||
UniValue outputs = params[2].get_obj();
|
||||
|
||||
CAmount vpub_old(0);
|
||||
CAmount vpub_new(0);
|
||||
|
||||
int nextBlockHeight = chainActive.Height() + 1;
|
||||
|
||||
const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY);
|
||||
|
||||
if (params[3].get_real() != 0.0) {
|
||||
if (canopyActive) {
|
||||
throw JSONRPCError(RPC_VERIFY_REJECTED, "Sprout shielding is not supported after Canopy");
|
||||
}
|
||||
vpub_old = AmountFromValue(params[3]);
|
||||
}
|
||||
|
||||
if (params[4].get_real() != 0.0)
|
||||
vpub_new = AmountFromValue(params[4]);
|
||||
|
||||
std::vector<JSInput> vjsin;
|
||||
std::vector<JSOutput> vjsout;
|
||||
std::vector<SproutNote> notes;
|
||||
std::vector<SproutSpendingKey> keys;
|
||||
std::vector<uint256> commitments;
|
||||
|
||||
KeyIO keyIO(Params());
|
||||
for (const string& name_ : inputs.getKeys()) {
|
||||
auto spendingkey = keyIO.DecodeSpendingKey(inputs[name_].get_str());
|
||||
if (!spendingkey.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||
}
|
||||
if (std::get_if<libzcash::SproutSpendingKey>(&spendingkey.value()) == nullptr) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
|
||||
}
|
||||
SproutSpendingKey k = std::get<libzcash::SproutSpendingKey>(spendingkey.value());
|
||||
|
||||
keys.push_back(k);
|
||||
|
||||
SproutNotePlaintext npt;
|
||||
|
||||
{
|
||||
CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssData >> npt;
|
||||
}
|
||||
|
||||
SproutPaymentAddress addr = k.address();
|
||||
SproutNote note = npt.note(addr);
|
||||
notes.push_back(note);
|
||||
commitments.push_back(note.cm());
|
||||
}
|
||||
|
||||
uint256 anchor;
|
||||
std::vector<std::optional<SproutWitness>> witnesses;
|
||||
pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
|
||||
|
||||
assert(witnesses.size() == notes.size());
|
||||
assert(notes.size() == keys.size());
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < witnesses.size(); i++) {
|
||||
if (!witnesses[i]) {
|
||||
throw runtime_error(
|
||||
"joinsplit input could not be found in tree"
|
||||
);
|
||||
}
|
||||
|
||||
vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
|
||||
}
|
||||
}
|
||||
|
||||
while (vjsin.size() < ZC_NUM_JS_INPUTS) {
|
||||
vjsin.push_back(JSInput());
|
||||
}
|
||||
|
||||
for (const string& name_ : outputs.getKeys()) {
|
||||
auto addrToDecoded = keyIO.DecodePaymentAddress(name_);
|
||||
if (!addrToDecoded.has_value()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
|
||||
}
|
||||
|
||||
libzcash::PaymentAddress addrTo(addrToDecoded.value());
|
||||
if (!std::holds_alternative<libzcash::SproutPaymentAddress>(addrTo)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout payment addresses");
|
||||
}
|
||||
CAmount nAmount = AmountFromValue(outputs[name_]);
|
||||
|
||||
vjsout.push_back(JSOutput(std::get<libzcash::SproutPaymentAddress>(addrTo), nAmount));
|
||||
}
|
||||
|
||||
while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
|
||||
vjsout.push_back(JSOutput());
|
||||
}
|
||||
|
||||
// TODO
|
||||
if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
|
||||
throw runtime_error("unsupported joinsplit input/output counts");
|
||||
}
|
||||
|
||||
Ed25519VerificationKey joinSplitPubKey;
|
||||
Ed25519SigningKey joinSplitPrivKey;
|
||||
ed25519_generate_keypair(&joinSplitPrivKey, &joinSplitPubKey);
|
||||
|
||||
CMutableTransaction mtx(tx);
|
||||
mtx.nVersion = 4;
|
||||
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
|
||||
mtx.joinSplitPubKey = joinSplitPubKey;
|
||||
|
||||
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> jsInputs({vjsin[0], vjsin[1]});
|
||||
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> jsIutputs({vjsout[0], vjsout[1]});
|
||||
auto jsdesc = JSDescriptionInfo(joinSplitPubKey,
|
||||
anchor,
|
||||
jsInputs,
|
||||
jsIutputs,
|
||||
vpub_old,
|
||||
vpub_new).BuildDeterministic();
|
||||
|
||||
{
|
||||
auto verifier = ProofVerifier::Strict();
|
||||
assert(verifier.VerifySprout(jsdesc, joinSplitPubKey));
|
||||
}
|
||||
|
||||
mtx.vJoinSplit.push_back(jsdesc);
|
||||
|
||||
// Empty output script.
|
||||
CScript scriptCode;
|
||||
CTransaction signTx(mtx);
|
||||
// This API will never support v5+ transactions, and can ignore ZIP 244.
|
||||
PrecomputedTransactionData txdata(signTx, {});
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata);
|
||||
|
||||
// Add the signature
|
||||
assert(ed25519_sign(
|
||||
&joinSplitPrivKey,
|
||||
dataToBeSigned.begin(), 32,
|
||||
&mtx.joinSplitSig));
|
||||
|
||||
// Sanity check
|
||||
assert(ed25519_verify(
|
||||
&mtx.joinSplitPubKey,
|
||||
&mtx.joinSplitSig,
|
||||
dataToBeSigned.begin(), 32));
|
||||
|
||||
CTransaction rawTx(mtx);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << rawTx;
|
||||
|
||||
std::string encryptedNote1;
|
||||
std::string encryptedNote2;
|
||||
{
|
||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss2 << ((unsigned char) 0x00);
|
||||
ss2 << jsdesc.ephemeralKey;
|
||||
ss2 << jsdesc.ciphertexts[0];
|
||||
ss2 << ZCJoinSplit::h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
|
||||
|
||||
encryptedNote1 = HexStr(ss2.begin(), ss2.end());
|
||||
}
|
||||
{
|
||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss2 << ((unsigned char) 0x01);
|
||||
ss2 << jsdesc.ephemeralKey;
|
||||
ss2 << jsdesc.ciphertexts[1];
|
||||
ss2 << ZCJoinSplit::h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
|
||||
|
||||
encryptedNote2 = HexStr(ss2.begin(), ss2.end());
|
||||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("encryptednote1", encryptedNote1);
|
||||
result.pushKV("encryptednote2", encryptedNote2);
|
||||
result.pushKV("rawtxn", HexStr(ss.begin(), ss.end()));
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (!fEnableZCRawKeygen)
|
||||
throw runtime_error(
|
||||
"zcrawkeygen is DEPRECATED and will be removed in a future release\n"
|
||||
"\nrestart with `-allowdeprecated=zcrawkeygen` if you require backward compatibility.\n"
|
||||
"See https://zcash.github.io/zcash/user/deprecation.html for more information.");
|
||||
|
||||
if (fHelp || params.size() != 0) {
|
||||
throw runtime_error(
|
||||
"zcrawkeygen\n"
|
||||
"\n"
|
||||
"DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
|
||||
"\n"
|
||||
"Output: {\n"
|
||||
" \"zcaddress\": zcaddr,\n"
|
||||
" \"zcsecretkey\": zcsecretkey,\n"
|
||||
" \"zcviewingkey\": zcviewingkey,\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
auto k = SproutSpendingKey::random();
|
||||
auto addr = k.address();
|
||||
auto viewing_key = k.viewing_key();
|
||||
|
||||
KeyIO keyIO(Params());
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("zcaddress", keyIO.EncodePaymentAddress(addr));
|
||||
result.pushKV("zcsecretkey", keyIO.EncodeSpendingKey(k));
|
||||
result.pushKV("zcviewingkey", keyIO.EncodeViewingKey(viewing_key));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
UniValue z_getnewaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
|
@ -6414,9 +6060,6 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "walletpassphrase", &walletpassphrase, true },
|
||||
{ "wallet", "walletconfirmbackup", &walletconfirmbackup, true },
|
||||
{ "wallet", "zcbenchmark", &zc_benchmark, true },
|
||||
{ "wallet", "zcrawkeygen", &zc_raw_keygen, true },
|
||||
{ "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
|
||||
{ "wallet", "zcrawreceive", &zc_raw_receive, true },
|
||||
{ "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true },
|
||||
{ "wallet", "z_listreceivedbyaddress", &z_listreceivedbyaddress, false },
|
||||
{ "wallet", "z_listunspent", &z_listunspent, false },
|
||||
|
|
Loading…
Reference in New Issue