Merge remote-tracking branch 'zcash/master' into dPoW

This commit is contained in:
jl777
2016-10-28 13:50:21 -03:00
137 changed files with 5475 additions and 1453 deletions

View File

@@ -29,6 +29,23 @@
using namespace libzcash;
int find_output(Object obj, int n) {
Value outputMapValue = find_value(obj, "outputmap");
if (outputMapValue.type() != array_type) {
throw JSONRPCError(RPC_WALLET_ERROR, "Missing outputmap for JoinSplit operation");
}
Array outputMap = outputMapValue.get_array();
assert(outputMap.size() == ZC_NUM_JS_OUTPUTS);
for (size_t i = 0; i < outputMap.size(); i++) {
if (outputMap[i] == n) {
return i;
}
}
throw std::logic_error("n is not present in outputmap");
}
AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
std::string fromAddress,
std::vector<SendManyRecipient> tOutputs,
@@ -179,12 +196,15 @@ bool AsyncRPCOperation_sendmany::main_impl() {
CAmount sendAmount = z_outputs_total + t_outputs_total;
CAmount targetAmount = sendAmount + minersFee;
assert(!isfromtaddr_ || z_inputs_total == 0);
assert(!isfromzaddr_ || t_inputs_total == 0);
if (isfromtaddr_ && (t_inputs_total < targetAmount)) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strprintf("Insufficient transparent funds, have %ld, need %ld plus fee %ld", t_inputs_total, t_outputs_total, minersFee));
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strprintf("Insufficient transparent funds, have %ld, need %ld", t_inputs_total, targetAmount));
}
if (isfromzaddr_ && (z_inputs_total < targetAmount)) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strprintf("Insufficient protected funds, have %ld, need %ld plus fee %ld", z_inputs_total, z_outputs_total, minersFee));
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strprintf("Insufficient protected funds, have %ld, need %ld", z_inputs_total, targetAmount));
}
// If from address is a taddr, select UTXOs to spend
@@ -284,8 +304,9 @@ bool AsyncRPCOperation_sendmany::main_impl() {
* -> zaddrs
*
* Note: Consensus rule states that coinbase utxos can only be sent to a zaddr.
* Any change over and above the amount specified by the user will be sent
* to the same zaddr the user is sending funds to.
* Local wallet rule does not allow any change when sending coinbase utxos
* since there is currently no way to specify a change address and we don't
* want users accidentally sending excess funds to a recipient.
*/
if (isfromtaddr_) {
add_taddr_outputs_to_tx();
@@ -294,25 +315,13 @@ bool AsyncRPCOperation_sendmany::main_impl() {
CAmount fundsSpent = t_outputs_total + minersFee + z_outputs_total;
CAmount change = funds - fundsSpent;
// If there is a single zaddr and there are coinbase utxos, change goes to the zaddr.
if (change > 0) {
if (isSingleZaddrOutput && selectedUTXOCoinbase) {
std::string address = std::get<0>(zOutputsDeque.front());
SendManyRecipient smr(address, change, std::string());
zOutputsDeque.push_back(smr);
LogPrint("zrpc", "%s: change from coinbase utxo is also sent to the recipient (amount=%s)\n",
getId().substr(0, 10),
FormatMoney(change, false)
);
} else if (!isSingleZaddrOutput && selectedUTXOCoinbase) {
// This should not happen and is not allowed
assert(false);
if (selectedUTXOCoinbase) {
assert(isSingleZaddrOutput);
throw JSONRPCError(RPC_WALLET_ERROR, strprintf(
"Change %ld not allowed. When protecting coinbase funds, the wallet does not allow any change as there is currently no way to specify a change address in z_sendmany.", change));
} else {
// If there is a single zaddr and no coinbase utxos, just use a regular output for change.
add_taddr_change_output_to_tx(change);
LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
getId().substr(0, 10),
FormatMoney(change, false)
@@ -372,6 +381,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
*/
Object obj;
CAmount jsChange = 0; // this is updated after each joinsplit
int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0
bool minersFeeProcessed = false;
if (t_outputs_total > 0) {
@@ -429,6 +439,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
}
obj = perform_joinsplit(info, outPoints);
if (jsChange > 0) {
changeOutputIndex = find_output(obj, 1);
}
}
}
@@ -442,9 +456,6 @@ bool AsyncRPCOperation_sendmany::main_impl() {
// Keep track of treestate within this transaction
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
std::vector<uint256> previousCommitments;
// NOTE: Randomization of input and output order could break this in future
const int changeOutputIndex = 1;
while (zOutputsDeque.size() > 0) {
AsyncJoinSplitInfo info;
@@ -483,7 +494,6 @@ bool AsyncRPCOperation_sendmany::main_impl() {
throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor");
}
// NOTE: We assume the last commitment, output 1, is the change we want
for (const uint256& commitment : prevJoinSplit.commitments) {
tree.append(commitment);
previousCommitments.push_back(commitment);
@@ -645,6 +655,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
}
obj = perform_joinsplit(info, witnesses, jsAnchor);
if (jsChange > 0) {
changeOutputIndex = find_output(obj, 1);
}
}
}
@@ -758,7 +772,8 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
for (CNotePlaintextEntry & entry : entries) {
z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(frompaymentaddress_), CAmount(entry.plaintext.value)));
std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
LogPrint("zrpc", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
if (LogAcceptCategory("zrpcunsafe")) {
LogPrint("zrpcunsafe", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
getId().substr(0, 10),
entry.jsop.hash.ToString().substr(0, 10),
entry.jsop.js,
@@ -766,6 +781,15 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
FormatMoney(entry.plaintext.value, false),
HexStr(data).substr(0, 10)
);
} else {
LogPrint("zrpc", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
getId().substr(0, 10),
entry.jsop.hash.ToString().substr(0, 10),
entry.jsop.js,
int(entry.jsop.n), // uint8_t
FormatMoney(entry.plaintext.value, false)
);
}
}
if (z_inputs_.size() == 0) {
@@ -845,11 +869,20 @@ Object AsyncRPCOperation_sendmany::perform_joinsplit(
);
// Generate the proof, this can take over a minute.
JSDescription jsdesc(*pzcashParams,
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs
{info.vjsin[0], info.vjsin[1]};
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs
{info.vjsout[0], info.vjsout[1]};
boost::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
boost::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
JSDescription jsdesc = JSDescription::Randomized(
*pzcashParams,
joinSplitPubKey_,
anchor,
{info.vjsin[0], info.vjsin[1]},
{info.vjsout[0], info.vjsout[1]},
inputs,
outputs,
inputMap,
outputMap,
info.vpub_old,
info.vpub_new,
!this->testmode);
@@ -910,10 +943,21 @@ Object AsyncRPCOperation_sendmany::perform_joinsplit(
encryptedNote2 = HexStr(ss2.begin(), ss2.end());
}
Array arrInputMap;
Array arrOutputMap;
for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) {
arrInputMap.push_back(inputMap[i]);
}
for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
arrOutputMap.push_back(outputMap[i]);
}
Object obj;
obj.push_back(Pair("encryptednote1", encryptedNote1));
obj.push_back(Pair("encryptednote2", encryptedNote2));
obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
obj.push_back(Pair("inputmap", arrInputMap));
obj.push_back(Pair("outputmap", arrOutputMap));
return obj;
}

View File

@@ -11,9 +11,11 @@
#include "zcash/Note.hpp"
#include "zcash/NoteEncryption.hpp"
#include <boost/filesystem.hpp>
using ::testing::Return;
ZCJoinSplit* params = ZCJoinSplit::Unopened();
extern ZCJoinSplit* params;
ACTION(ThrowLogicError) {
throw std::logic_error("Boom");
@@ -178,6 +180,13 @@ CWalletTx GetValidSpend(const libzcash::SpendingKey& sk,
return wtx;
}
TEST(wallet_tests, setup_datadir_location_run_as_first_test) {
// Get temporary and unique path for file.
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
boost::filesystem::create_directories(pathTemp);
mapArgs["-datadir"] = pathTemp.string();
}
TEST(wallet_tests, note_data_serialisation) {
auto sk = libzcash::SpendingKey::random();
auto wtx = GetValidReceive(sk, 10, true);
@@ -734,6 +743,14 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
wallet.GetNoteWitnesses(notes, witnesses, anchor4);
EXPECT_TRUE((bool) witnesses[0]);
EXPECT_EQ(anchor2, anchor4);
// Incrementing with the same block again should not change the cache
uint256 anchor5;
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
std::vector<boost::optional<ZCIncrementalWitness>> witnesses5;
wallet.GetNoteWitnesses(notes, witnesses5, anchor5);
EXPECT_EQ(witnesses, witnesses5);
EXPECT_EQ(anchor4, anchor5);
}
}

View File

@@ -81,10 +81,10 @@ Value importprivkey(const Array& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
"importprivkey \"bitcoinprivkey\" ( \"label\" rescan )\n"
"importprivkey \"zcashprivkey\" ( \"label\" rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
"\nArguments:\n"
"1. \"bitcoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
"1. \"zcashprivkey\" (string, required) The private key (see dumpprivkey)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
@@ -182,7 +182,7 @@ Value importaddress(const Array& params, bool fHelp)
std::vector<unsigned char> data(ParseHex(params[0].get_str()));
script = CScript(data.begin(), data.end());
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address or script");
}
string strLabel = "";
@@ -321,7 +321,7 @@ Value importwallet_impl(const Array& params, bool fHelp, bool fImportZKeys)
}
catch (const std::runtime_error &e) {
LogPrint("zrpc","Importing detected an error: %s\n", e.what());
// Not a valid spending key, so carry on and see if it's a Bitcoin style address.
// Not a valid spending key, so carry on and see if it's a Zcash style address.
}
}
@@ -388,11 +388,11 @@ Value dumpprivkey(const Array& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"dumpprivkey \"bitcoinaddress\"\n"
"\nReveals the private key corresponding to 'bitcoinaddress'.\n"
"dumpprivkey \"zcashaddress\"\n"
"\nReveals the private key corresponding to 'zcashaddress'.\n"
"Then the importprivkey can be used with this output\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address for the private key\n"
"1. \"zcashaddress\" (string, required) The zcash address for the private key\n"
"\nResult:\n"
"\"key\" (string) The private key\n"
"\nExamples:\n"
@@ -408,7 +408,7 @@ Value dumpprivkey(const Array& params, bool fHelp)
string strAddress = params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
CKeyID keyID;
if (!address.GetKeyID(keyID))
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");

View File

@@ -114,11 +114,11 @@ Value getnewaddress(const Array& params, bool fHelp)
if (fHelp || params.size() > 1)
throw runtime_error(
"getnewaddress ( \"account\" )\n"
"\nReturns a new Bitcoin address for receiving payments.\n"
"\nReturns a new Zcash address for receiving payments.\n"
"\nArguments:\n"
"1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nResult:\n"
"\"bitcoinaddress\" (string) The new bitcoin address\n"
"\"zcashaddress\" (string) The new zcash address\n"
"\nExamples:\n"
+ HelpExampleCli("getnewaddress", "")
+ HelpExampleRpc("getnewaddress", "")
@@ -191,11 +191,11 @@ Value getaccountaddress(const Array& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccountaddress \"account\"\n"
"\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
"\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
"\nArguments:\n"
"1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nResult:\n"
"\"bitcoinaddress\" (string) The account bitcoin address\n"
"\"zcashaddress\" (string) The account zcash address\n"
"\nExamples:\n"
+ HelpExampleCli("getaccountaddress", "")
+ HelpExampleCli("getaccountaddress", "\"\"")
@@ -223,7 +223,7 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
if (fHelp || params.size() > 1)
throw runtime_error(
"getrawchangeaddress\n"
"\nReturns a new Bitcoin address, for receiving change.\n"
"\nReturns a new Zcash address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n"
"\nResult:\n"
"\"address\" (string) The address\n"
@@ -257,10 +257,10 @@ Value setaccount(const Array& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setaccount \"bitcoinaddress\" \"account\"\n"
"setaccount \"zcashaddress\" \"account\"\n"
"\nDEPRECATED. Sets the account associated with the given address.\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\n"
"1. \"zcashaddress\" (string, required) The zcash address to be associated with an account.\n"
"2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nExamples:\n"
+ HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
@@ -271,7 +271,7 @@ Value setaccount(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
string strAccount;
if (params.size() > 1)
@@ -303,10 +303,10 @@ Value getaccount(const Array& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccount \"bitcoinaddress\"\n"
"getaccount \"zcashaddress\"\n"
"\nDEPRECATED. Returns the account associated with the given address.\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address for account lookup.\n"
"1. \"zcashaddress\" (string, required) The zcash address for account lookup.\n"
"\nResult:\n"
"\"accountname\" (string) the account address\n"
"\nExamples:\n"
@@ -318,7 +318,7 @@ Value getaccount(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
string strAccount;
map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
@@ -341,7 +341,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
"1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nResult:\n"
"[ (json array of string)\n"
" \"bitcoinaddress\" (string) a bitcoin address associated with the given account\n"
" \"zcashaddress\" (string) a zcash address associated with the given account\n"
" ,...\n"
"]\n"
"\nExamples:\n"
@@ -376,7 +376,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
if (nValue > curBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
// Parse Bitcoin address
// Parse Zcash address
CScript scriptPubKey = GetScriptForDestination(address);
// Create and send the transaction
@@ -417,11 +417,11 @@ Value sendtoaddress(const Array& params, bool fHelp)
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
"sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
"sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
"\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
+ HelpRequiringPassphrase() +
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
"1. \"zcashaddress\" (string, required) The zcash address to send to.\n"
"2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
"3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
@@ -429,7 +429,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
" to which you're sending the transaction. This is not part of the \n"
" transaction, just kept in your wallet.\n"
"5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
" The recipient will receive less bitcoins than you enter in the amount field.\n"
" The recipient will receive less zcash than you enter in the amount field.\n"
"\nResult:\n"
"\"transactionid\" (string) The transaction id.\n"
"\nExamples:\n"
@@ -443,7 +443,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
// Amount
CAmount nAmount = AmountFromValue(params[1]);
@@ -519,7 +519,7 @@ Value listaddressgroupings(const Array& params, bool fHelp)
"[\n"
" [\n"
" [\n"
" \"bitcoinaddress\", (string) The bitcoin address\n"
" \"zcashaddress\", (string) The zcash address\n"
" amount, (numeric) The amount in btc\n"
" \"account\" (string, optional) The account (DEPRECATED)\n"
" ]\n"
@@ -562,11 +562,11 @@ Value signmessage(const Array& params, bool fHelp)
if (fHelp || params.size() != 2)
throw runtime_error(
"signmessage \"bitcoinaddress\" \"message\"\n"
"signmessage \"zcashaddress\" \"message\"\n"
"\nSign a message with the private key of an address"
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the private key.\n"
"1. \"zcashaddress\" (string, required) The zcash address to use for the private key.\n"
"2. \"message\" (string, required) The message to create a signature of.\n"
"\nResult:\n"
"\"signature\" (string) The signature of the message encoded in base 64\n"
@@ -618,10 +618,10 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
"\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
"getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
"\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
"1. \"zcashaddress\" (string, required) The zcash address for transactions.\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
"amount (numeric) The total amount in btc received at this address.\n"
@@ -641,7 +641,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
// Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
CScript scriptPubKey = GetScriptForDestination(address.Get());
if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0;
@@ -923,13 +923,13 @@ Value sendfrom(const Array& params, bool fHelp)
if (fHelp || params.size() < 3 || params.size() > 6)
throw runtime_error(
"sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
"\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address.\n"
"sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
"\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a zcash address.\n"
"The amount is a real and is rounded to the nearest 0.00000001."
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
"2. \"tozcashaddress\" (string, required) The zcash address to send funds to.\n"
"3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
"4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
"5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
@@ -953,7 +953,7 @@ Value sendfrom(const Array& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
CAmount nAmount = AmountFromValue(params[2]);
int nMinDepth = 1;
if (params.size() > 3)
@@ -993,14 +993,14 @@ Value sendmany(const Array& params, bool fHelp)
"1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"2. \"amounts\" (string, required) A json object with addresses and amounts\n"
" {\n"
" \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
" \"address\":amount (numeric) The zcash address is the key, the numeric amount in btc is the value\n"
" ,...\n"
" }\n"
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
"4. \"comment\" (string, optional) A comment\n"
"5. subtractfeefromamount (string, optional) A json array with addresses.\n"
" The fee will be equally deducted from the amount of each selected address.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" Those recipients will receive less zcashs than you enter in their corresponding amount field.\n"
" If no addresses are specified here, the sender pays the fee.\n"
" [\n"
" \"address\" (string) Subtract fee from this address\n"
@@ -1045,7 +1045,7 @@ Value sendmany(const Array& params, bool fHelp)
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
@@ -1097,20 +1097,20 @@ Value addmultisigaddress(const Array& params, bool fHelp)
{
string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
"\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"Each key is a Zcash address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n"
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
"2. \"keysobject\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
"2. \"keysobject\" (string, required) A json array of zcash addresses or hex-encoded public keys\n"
" [\n"
" \"address\" (string) bitcoin address or hex-encoded public key\n"
" \"address\" (string) zcash address or hex-encoded public key\n"
" ...,\n"
" ]\n"
"3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nResult:\n"
"\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
"\"zcashaddress\" (string) A zcash address associated with the keys.\n"
"\nExamples:\n"
"\nAdd a multisig address from 2 addresses\n"
@@ -1455,7 +1455,7 @@ Value listtransactions(const Array& params, bool fHelp)
" {\n"
" \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
" It will be \"\" for the default account.\n"
" \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n"
" \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for \n"
" move transactions (category = move).\n"
" \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
" transaction between accounts, and not associated with an address,\n"
@@ -1647,7 +1647,7 @@ Value listsinceblock(const Array& params, bool fHelp)
"{\n"
" \"transactions\": [\n"
" \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
" \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
" \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for move transactions (category = move).\n"
" \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
" \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
" outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
@@ -1746,7 +1746,7 @@ Value gettransaction(const Array& params, bool fHelp)
" \"details\" : [\n"
" {\n"
" \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
" \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
" \"address\" : \"zcashaddress\", (string) The zcash address involved in the transaction\n"
" \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
" \"amount\" : x.xxx (numeric) The amount in btc\n"
" \"vout\" : n, (numeric) the vout value\n"
@@ -1889,7 +1889,7 @@ Value walletpassphrase(const Array& params, bool fHelp)
throw runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
"This is needed prior to performing transactions related to private keys such as sending zcash\n"
"\nArguments:\n"
"1. \"passphrase\" (string, required) The wallet passphrase\n"
"2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
@@ -2031,10 +2031,18 @@ Value encryptwallet(const Array& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return Value::null;
auto fEnableWalletEncryption = GetBoolArg("-developerencryptwallet", false);
std::string strWalletEncryptionDisabledMsg = "";
if (!fEnableWalletEncryption) {
strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
}
if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
throw runtime_error(
"encryptwallet \"passphrase\"\n"
+ strWalletEncryptionDisabledMsg +
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
"After this, any calls that interact with private keys such as sending or signing \n"
"will require the passphrase to be set prior the making these calls.\n"
@@ -2046,10 +2054,10 @@ Value encryptwallet(const Array& params, bool fHelp)
"\nExamples:\n"
"\nEncrypt you wallet\n"
+ HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
"\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
"\nNow set the passphrase to use the wallet, such as for signing or sending zcash\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
"\nNow we can so something like sign\n"
+ HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
+ HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
"\nNow lock the wallet again by removing the passphrase\n"
+ HelpExampleCli("walletlock", "") +
"\nAs a json rpc call\n"
@@ -2060,6 +2068,9 @@ Value encryptwallet(const Array& params, bool fHelp)
if (fHelp)
return true;
if (!fEnableWalletEncryption) {
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
}
if (pwalletMain->IsCrypted())
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
@@ -2081,7 +2092,7 @@ Value encryptwallet(const Array& params, bool fHelp)
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
StartShutdown();
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
}
Value lockunspent(const Array& params, bool fHelp)
@@ -2094,7 +2105,7 @@ Value lockunspent(const Array& params, bool fHelp)
"lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
"\nUpdates list of temporarily unspendable outputs.\n"
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
"A locked transaction output will not be chosen by automatic coin selection, when spending zcash.\n"
"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
"is always cleared (by virtue of process exit) when a node stops or fails.\n"
"Also see the listunspent call\n"
@@ -2258,8 +2269,8 @@ Value getwalletinfo(const Array& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
" \"balance\": xxxxxxx, (numeric) the total confirmed bitcoin balance of the wallet\n"
" \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed bitcoin balance of the wallet\n"
" \"balance\": xxxxxxx, (numeric) the total confirmed zcash balance of the wallet\n"
" \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed zcash balance of the wallet\n"
" \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
@@ -2329,9 +2340,9 @@ Value listunspent(const Array& params, bool fHelp)
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
"3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
"3. \"addresses\" (string) A json array of zcash addresses to filter\n"
" [\n"
" \"address\" (string) bitcoin address\n"
" \"address\" (string) zcash address\n"
" ,...\n"
" ]\n"
"\nResult\n"
@@ -2339,7 +2350,7 @@ Value listunspent(const Array& params, bool fHelp)
" {\n"
" \"txid\" : \"txid\", (string) the transaction id \n"
" \"vout\" : n, (numeric) the vout value\n"
" \"address\" : \"address\", (string) the bitcoin address\n"
" \"address\" : \"address\", (string) the zcash address\n"
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
" \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
@@ -2370,7 +2381,7 @@ Value listunspent(const Array& params, bool fHelp)
BOOST_FOREACH(Value& input, inputs) {
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address);
@@ -3230,6 +3241,7 @@ Value z_sendmany(const Array& params, bool fHelp)
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf )\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
"\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
"\nWhen sending coinbase UTXOs to a zaddr, change is not alllowed. The entire value of the UTXO(s) must be consumed."
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
@@ -3287,8 +3299,6 @@ Value z_sendmany(const Array& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
const Object& o = output.get_obj();
RPCTypeCheck(o, boost::assign::map_list_of("address", str_type)("amount", real_type));
// sanity check, report error if unknown key-value pairs
for (const Pair& p : o) {
std::string s = p.name_;

View File

@@ -699,7 +699,23 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
JSOutPoint jsoutpt {hash, i, j};
if (mapWallet[hash].mapNoteData.count(jsoutpt)) {
CNoteData* nd = &(mapWallet[hash].mapNoteData[jsoutpt]);
assert(nd->witnesses.size() == 0);
if (nd->witnesses.size() > 0) {
// We think this can happen because we write out the
// witness cache state after every block increment or
// decrement, but the block index itself is written in
// batches. So if the node crashes in between these two
// operations, it is possible for IncrementNoteWitnesses
// to be called again on previously-cached blocks. This
// doesn't affect existing cached notes because of the
// CNoteData::witnessHeight checks. See #1378 for details.
LogPrintf("Inconsistent witness cache state found for %s\n- Cache size: %d\n- Top (height %d): %s\n- New (height %d): %s\n",
jsoutpt.ToString(), nd->witnesses.size(),
nd->witnessHeight,
nd->witnesses.front().root().GetHex(),
pindex->nHeight,
tree.witness().root().GetHex());
nd->witnesses.clear();
}
nd->witnesses.push_front(tree.witness());
// Set height to one less than pindex so it gets incremented
nd->witnessHeight = pindex->nHeight - 1;

View File

@@ -885,7 +885,7 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
void ThreadFlushWalletDB(const string& strFile)
{
// Make this thread recognisable as the wallet flushing thread
RenameThread("bitcoin-wallet");
RenameThread("zcash-wallet");
static bool fOneThread;
if (fOneThread)