Browse Source

Start to implement z_createrawtransaction for making raw shielded transactions

Inspired by these aging issues, which have not been revisited since
Sapling was enabled:

https://github.com/zcash/zcash/issues/2666
https://github.com/zcash/zcash/issues/2542
z_createrawtransaction
Jonathan "Duke" Leto 5 years ago
parent
commit
1bcec40b97
  1. 1
      src/rpc/server.cpp
  2. 1
      src/rpc/server.h
  3. 85
      src/wallet/rpcwallet.cpp

1
src/rpc/server.cpp

@ -636,6 +636,7 @@ static const CRPCCommand vRPCCommands[] =
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
{ "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
{ "wallet", "z_sendmany", &z_sendmany, false },
{ "wallet", "z_createrawtransaction", &z_createrawtransaction, true },
{ "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
{ "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
{ "wallet", "z_getoperationresult", &z_getoperationresult, true },

1
src/rpc/server.h

@ -468,6 +468,7 @@ extern UniValue z_getbalance(const UniValue& params, bool fHelp); // in rpcwalle
extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue z_sendmany(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue z_createrawtransaction(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue z_getoperationresult(const UniValue& params, bool fHelp); // in rpcwallet.cpp

85
src/wallet/rpcwallet.cpp

@ -4509,6 +4509,91 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
return operationId;
}
UniValue z_createrawtransaction(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 4)
throw runtime_error(
"z_createrawtransaction ...\n"
"\nCreate a raw shielded transaction, involving at least one shielded input or output. Amounts are decimal numbers with at most 8 digits of precision."
);
LOCK2(cs_main, pwalletMain->cs_wallet);
UniValue inputs = params[0].get_array();
UniValue outputs = params[1].get_array();
if (outputs.size()==0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
for (const UniValue& o : outputs.getValues()) {
if (!o.isObject())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
// sanity check, report error if unknown key-value pairs
for (const string& name_ : o.getKeys()) {
std::string s = name_;
if (s != "address" && s != "amount" && s!="memo")
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
}
string address = find_value(o, "address").get_str();
bool isZaddr = false;
CTxDestination taddr = DecodeDestination(address);
if (!IsValidDestination(taddr)) {
auto res = DecodePaymentAddress(address);
if (IsValidPaymentAddress(res, branchId)) {
isZaddr = true;
bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
bool toSprout = !toSapling;
noSproutAddrs = noSproutAddrs && toSapling;
containsSproutOutput |= toSprout;
containsSaplingOutput |= toSapling;
if ( GetTime() > KOMODO_SAPLING_DEADLINE )
{
if ( fromSprout || toSprout )
throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage has expired");
}
}
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
}
}
setAddress.insert(address);
UniValue memoValue = find_value(o, "memo");
string memo;
if (!memoValue.isNull()) {
memo = memoValue.get_str();
if (!isZaddr) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
} else if (!IsHex(memo)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
}
if (memo.length() > ZC_MEMO_SIZE*2) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
}
}
UniValue av = find_value(o, "amount");
CAmount nAmount = AmountFromValue( av );
if (nAmount < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
if (isZaddr) {
zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
} else {
taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
}
nTotalOut += nAmount;
}
}
/**
When estimating the number of coinbase utxos we can shield in a single transaction:

Loading…
Cancel
Save