214 lines
6.8 KiB
C++
214 lines
6.8 KiB
C++
// Copyright (c) 2017-2023 The Zcash developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
|
|
|
#include "asyncrpcoperation_mergetoaddress.h"
|
|
|
|
#include "amount.h"
|
|
#include "asyncrpcoperation_common.h"
|
|
#include "asyncrpcqueue.h"
|
|
#include "core_io.h"
|
|
#include "experimental_features.h"
|
|
#include "init.h"
|
|
#include "key_io.h"
|
|
#include "main.h"
|
|
#include "miner.h"
|
|
#include "net.h"
|
|
#include "netbase.h"
|
|
#include "proof_verifier.h"
|
|
#include "rpc/protocol.h"
|
|
#include "rpc/server.h"
|
|
#include "script/interpreter.h"
|
|
#include "timedata.h"
|
|
#include "uint256.h"
|
|
#include "util/system.h"
|
|
#include "util/match.h"
|
|
#include "util/moneystr.h"
|
|
#include "util/time.h"
|
|
#include "wallet.h"
|
|
#include "walletdb.h"
|
|
#include "zcash/IncrementalMerkleTree.hpp"
|
|
|
|
#include <chrono>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <variant>
|
|
|
|
#include <rust/ed25519.h>
|
|
|
|
using namespace libzcash;
|
|
|
|
AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
|
|
CWallet& wallet,
|
|
TransactionStrategy strategy,
|
|
TransactionEffects effects,
|
|
UniValue contextInfo)
|
|
: strategy_(strategy), effects_(effects), contextinfo_(contextInfo)
|
|
{
|
|
effects.LockSpendable(*pwalletMain);
|
|
|
|
KeyIO keyIO(Params());
|
|
|
|
// Log the context info i.e. the call parameters to z_mergetoaddress
|
|
if (LogAcceptCategory("zrpcunsafe")) {
|
|
LogPrint("zrpcunsafe", "%s: z_mergetoaddress initialized (params=%s)\n", getId(), contextInfo.write());
|
|
} else {
|
|
LogPrint("zrpc", "%s: z_mergetoaddress initialized\n", getId());
|
|
}
|
|
}
|
|
|
|
AsyncRPCOperation_mergetoaddress::~AsyncRPCOperation_mergetoaddress()
|
|
{
|
|
}
|
|
|
|
std::pair<uint256, UniValue>
|
|
main_impl(
|
|
const CChainParams& chainparams,
|
|
CWallet& wallet,
|
|
const TransactionStrategy& strategy,
|
|
const TransactionEffects& effects,
|
|
const std::string& id,
|
|
bool testmode);
|
|
|
|
void AsyncRPCOperation_mergetoaddress::main()
|
|
{
|
|
set_state(OperationStatus::EXECUTING);
|
|
start_execution_clock();
|
|
|
|
bool success = false;
|
|
|
|
#ifdef ENABLE_MINING
|
|
GenerateBitcoins(false, 0, Params());
|
|
#endif
|
|
|
|
std::optional<uint256> txid;
|
|
try {
|
|
UniValue sendResult;
|
|
std::tie(txid, sendResult) =
|
|
main_impl(Params(), *pwalletMain, strategy_, effects_, getId(), testmode);
|
|
set_result(sendResult);
|
|
} catch (const UniValue& objError) {
|
|
int code = find_value(objError, "code").get_int();
|
|
std::string message = find_value(objError, "message").get_str();
|
|
set_error_code(code);
|
|
set_error_message(message);
|
|
} catch (const runtime_error& e) {
|
|
set_error_code(-1);
|
|
set_error_message("runtime error: " + string(e.what()));
|
|
} catch (const logic_error& e) {
|
|
set_error_code(-1);
|
|
set_error_message("logic error: " + string(e.what()));
|
|
} catch (const exception& e) {
|
|
set_error_code(-1);
|
|
set_error_message("general exception: " + string(e.what()));
|
|
} catch (...) {
|
|
set_error_code(-2);
|
|
set_error_message("unknown error");
|
|
}
|
|
|
|
#ifdef ENABLE_MINING
|
|
GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params());
|
|
#endif
|
|
|
|
stop_execution_clock();
|
|
|
|
if (txid.has_value()) {
|
|
set_state(OperationStatus::SUCCESS);
|
|
} else {
|
|
set_state(OperationStatus::FAILED);
|
|
}
|
|
|
|
std::string s = strprintf("%s: z_mergetoaddress finished (status=%s", getId(), getStateAsString());
|
|
if (txid.has_value()) {
|
|
s += strprintf(", txid=%s)\n", txid.value().GetHex());
|
|
} else {
|
|
s += strprintf(", error=%s)\n", getErrorMessage());
|
|
}
|
|
LogPrintf("%s", s);
|
|
}
|
|
|
|
std::pair<uint256, UniValue>
|
|
main_impl(
|
|
const CChainParams& chainparams,
|
|
CWallet& wallet,
|
|
const TransactionStrategy& strategy,
|
|
const TransactionEffects& effects,
|
|
const std::string& id,
|
|
bool testmode)
|
|
{
|
|
try {
|
|
const auto& spendable = effects.GetSpendable();
|
|
const auto& payments = effects.GetPayments();
|
|
spendable.LogInputs(id);
|
|
|
|
bool sendsToShielded = false;
|
|
for (const auto& resolvedPayment : payments.GetResolvedPayments()) {
|
|
sendsToShielded = sendsToShielded || examine(resolvedPayment.address, match {
|
|
[](const CKeyID&) { return true; },
|
|
[](const CScriptID&) { return true; },
|
|
[](const libzcash::SaplingPaymentAddress&) { return false; },
|
|
[](const libzcash::OrchardRawAddress&) { return false; },
|
|
});
|
|
}
|
|
if (spendable.sproutNoteEntries.empty()
|
|
&& spendable.saplingNoteEntries.empty()
|
|
&& spendable.orchardNoteMetadata.empty()
|
|
&& !sendsToShielded) {
|
|
LogPrint("zrpc", "%s: spending %s to send %s with fee %s\n",
|
|
id,
|
|
FormatMoney(payments.Total()),
|
|
FormatMoney(spendable.Total()),
|
|
FormatMoney(effects.GetFee()));
|
|
} else {
|
|
LogPrint("zrpcunsafe", "%s: spending %s to send %s with fee %s\n",
|
|
id,
|
|
FormatMoney(payments.Total()),
|
|
FormatMoney(spendable.Total()),
|
|
FormatMoney(effects.GetFee()));
|
|
}
|
|
LogPrint("zrpc", "%s: total transparent input: %s\n", id,
|
|
FormatMoney(spendable.GetTransparentTotal()));
|
|
LogPrint("zrpcunsafe", "%s: total shielded input: %s\n", id,
|
|
FormatMoney(spendable.GetSaplingTotal() + spendable.GetOrchardTotal()));
|
|
LogPrint("zrpc", "%s: total transparent output: %s\n", id,
|
|
FormatMoney(payments.GetTransparentTotal()));
|
|
LogPrint("zrpcunsafe", "%s: total shielded Sapling output: %s\n", id,
|
|
FormatMoney(payments.GetSaplingTotal()));
|
|
LogPrint("zrpcunsafe", "%s: total shielded Orchard output: %s\n", id,
|
|
FormatMoney(payments.GetOrchardTotal()));
|
|
LogPrint("zrpc", "%s: fee: %s\n", id, FormatMoney(effects.GetFee()));
|
|
|
|
auto buildResult = effects.ApproveAndBuild(
|
|
chainparams.GetConsensus(),
|
|
wallet,
|
|
chainActive,
|
|
strategy);
|
|
auto tx = buildResult.GetTxOrThrow();
|
|
|
|
UniValue sendResult = SendTransaction(tx, payments.GetResolvedPayments(), std::nullopt, testmode);
|
|
|
|
effects.UnlockSpendable(wallet);
|
|
return {tx.GetHash(), sendResult};
|
|
} catch (...) {
|
|
effects.UnlockSpendable(wallet);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Override getStatus() to append the operation's input parameters to the default status object.
|
|
*/
|
|
UniValue AsyncRPCOperation_mergetoaddress::getStatus() const
|
|
{
|
|
UniValue v = AsyncRPCOperation::getStatus();
|
|
if (contextinfo_.isNull()) {
|
|
return v;
|
|
}
|
|
|
|
UniValue obj = v.get_obj();
|
|
obj.pushKV("method", "z_mergetoaddress");
|
|
obj.pushKV("params", contextinfo_);
|
|
return obj;
|
|
}
|