From 5d86afef6a012962701f1385ea45533a660d640c Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sat, 12 Sep 2020 09:12:40 +0200 Subject: [PATCH 1/3] Port -txsend from str4d #37, https://github.com/zcash/zcash/pull/4522 --- src/init.cpp | 11 +++++++++++ src/rpc/rawtransaction.cpp | 16 ++++++++++++++++ src/wallet/wallet.cpp | 8 ++++++++ 3 files changed, 35 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index cd25e63fd..9f92999c4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -392,6 +392,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0)); + strUsage += HelpMessageOpt("-txsend=", _("Execute command to send a transaction instead of broadcasting (%s in cmd is replaced by transaction hex)")); strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX)); strUsage += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX)); strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX)); @@ -1118,6 +1119,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif } + if (mapArgs.count("-txsend")) { + if (GetBoolArg("-walletbroadcast", true)) { + if (SoftSetBoolArg("-walletbroadcast", false)) { + LogPrintf("%s: parameter interaction: -txsend= -> setting -walletbroadcast=0\n", __func__); + } else { + return InitError(_("Wallet transaction broadcasting is incompatible with -txsend (for privacy).")); + } + } + } + // ********************************************************* Step 3: parameter-to-internal-flags fZdebug=GetBoolArg("-zdebug", false); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 23327faf2..4b24081d7 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -45,7 +45,10 @@ #include +#include + #include +#include #include @@ -1373,6 +1376,19 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + + // If we are configured to send transactions via an + // external service instead of broadcasting, do that + std::string strCmd = GetArg("-txsend", ""); + if (!strCmd.empty()) { + if (fHaveChain) { + throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); + } + boost::replace_all(strCmd, "%s", EncodeHexTx(tx)); + boost::thread t(runCommand, strCmd); // thread runs free + // Return here so we don't add to our mempool or broadcast to peers + return hashTx.GetHex(); + } if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index fe8cbb4f7..a0cd0533f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3950,6 +3950,8 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // Track how many getdata requests our transaction gets mapRequestCount[wtxNew.GetHash()] = 0; + std::string strCmd = GetArg("-txsend", ""); + if (fBroadcastTransactions) { // Broadcast @@ -3962,6 +3964,12 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) } wtxNew.RelayWalletTransaction(); } + // If we are configured to send transactions via an + // external service instead of broadcasting, do that + else if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", EncodeHexTx(wtxNew)); + boost::thread t(runCommand, strCmd); // thread runs free + } } return true; } From 2075d0da25c03435e9c827170df974c7fe9efcc7 Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sat, 12 Sep 2020 10:01:33 +0200 Subject: [PATCH 2/3] Port scheduler race condition fix from BTC upstream #133, https://github.com/bitcoin/bitcoin/commit/12519bf62b8c49b1c1744eca6ea5b3162a61f962 --- src/scheduler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 08aba3225..2e1223b8e 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -66,9 +66,10 @@ void CScheduler::serviceQueue() // Some boost versions have a conflicting overload of wait_until that returns void. // Explicitly use a template here to avoid hitting that overload. - while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { - // Keep waiting until timeout + while (!shouldStop() && !taskQueue.empty()) { + boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; + if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) + break; // Exit loop after timeout, it means we reached the time of the event } // If there are multiple threads, the queue can empty while we're waiting (another From 702ea5fe91f11dc09a251dd8c6d7f6e5f392ba09 Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sat, 12 Sep 2020 15:11:52 +0200 Subject: [PATCH 3/3] delete joinsplit from rawtransactions #127 --- src/rpc/rawtransaction.cpp | 119 ------------------------------------- 1 file changed, 119 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4b24081d7..610e79149 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -85,65 +85,6 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud out.push_back(Pair("addresses", a)); } -UniValue TxJoinSplitToJSON(const CTransaction& tx) { - bool useGroth = tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION; - UniValue vjoinsplit(UniValue::VARR); - for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) { - const JSDescription& jsdescription = tx.vjoinsplit[i]; - UniValue joinsplit(UniValue::VOBJ); - - joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old))); - joinsplit.push_back(Pair("vpub_oldZat", jsdescription.vpub_old)); - joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new))); - joinsplit.push_back(Pair("vpub_newZat", jsdescription.vpub_new)); - - joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex())); - - { - UniValue nullifiers(UniValue::VARR); - BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) { - nullifiers.push_back(nf.GetHex()); - } - joinsplit.push_back(Pair("nullifiers", nullifiers)); - } - - { - UniValue commitments(UniValue::VARR); - BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) { - commitments.push_back(commitment.GetHex()); - } - joinsplit.push_back(Pair("commitments", commitments)); - } - - joinsplit.push_back(Pair("onetimePubKey", jsdescription.ephemeralKey.GetHex())); - joinsplit.push_back(Pair("randomSeed", jsdescription.randomSeed.GetHex())); - - { - UniValue macs(UniValue::VARR); - BOOST_FOREACH(const uint256 mac, jsdescription.macs) { - macs.push_back(mac.GetHex()); - } - joinsplit.push_back(Pair("macs", macs)); - } - - CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); - auto ps = SproutProofSerializer(ssProof, useGroth); - boost::apply_visitor(ps, jsdescription.proof); - joinsplit.push_back(Pair("proof", HexStr(ssProof.begin(), ssProof.end()))); - - { - UniValue ciphertexts(UniValue::VARR); - for (const ZCNoteEncryption::Ciphertext ct : jsdescription.ciphertexts) { - ciphertexts.push_back(HexStr(ct.begin(), ct.end())); - } - joinsplit.push_back(Pair("ciphertexts", ciphertexts)); - } - - vjoinsplit.push_back(joinsplit); - } - return vjoinsplit; -} - uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); UniValue TxShieldedSpendsToJSON(const CTransaction& tx) { @@ -309,9 +250,6 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& } entry.push_back(Pair("vout", vout)); - UniValue vjoinsplit = TxJoinSplitToJSON(tx); - entry.push_back(Pair("vjoinsplit", vjoinsplit)); - if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); @@ -393,9 +331,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) } entry.push_back(Pair("vout", vout)); - UniValue vjoinsplit = TxJoinSplitToJSON(tx); - entry.push_back(Pair("vjoinsplit", vjoinsplit)); - if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); @@ -481,33 +416,6 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp, const CPubKey& my " }\n" " ,...\n" " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value\n" - " \"vpub_new\" : x.xxx, (numeric) public output value\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" " \"blockhash\" : \"hash\", (string) the block hash\n" " \"confirmations\" : n, (numeric) The number of notarized DPoW confirmations\n" " \"rawconfirmations\" : n, (numeric) The number of raw confirmations\n" @@ -936,33 +844,6 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp, const CPubKey& " }\n" " ,...\n" " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value in HUSH\n" - " \"vpub_new\" : x.xxx, (numeric) public output value in HUSH\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" "}\n" "\nExamples:\n"