-
Notifications
You must be signed in to change notification settings - Fork 1.2k
merge bitcoin#14700...#16854: backports #4606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d9f8518
73ce859
afad681
5a69b85
15ebd14
c29d0c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // Copyright (c) 2009-2019 The Bitcoin Core developers | ||
| // Distributed under the MIT software license, see the accompanying | ||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
|
||
| #if defined(HAVE_CONFIG_H) | ||
| #include <config/dash-config.h> | ||
| #endif | ||
|
|
||
| #if defined(HAVE_SYS_SELECT_H) | ||
| #ifdef HAVE_CSTRING_DEPENDENT_FD_ZERO | ||
| #include <cstring> | ||
| #endif | ||
| #include <sys/select.h> | ||
|
|
||
| // trigger: Call FD_SET to trigger __fdelt_chk. FORTIFY_SOURCE must be defined | ||
| // as >0 and optimizations must be set to at least -O2. | ||
| // test: Add a file descriptor to an empty fd_set. Verify that it has been | ||
| // correctly added. | ||
| bool sanity_test_fdelt() | ||
| { | ||
| fd_set fds; | ||
| FD_ZERO(&fds); | ||
| FD_SET(0, &fds); | ||
| return FD_ISSET(0, &fds); | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| #include <chainparams.h> | ||
| #include <coins.h> | ||
| #include <consensus/validation.h> | ||
| #include <consensus/tx_verify.h> | ||
| #include <core_io.h> | ||
| #include <index/txindex.h> | ||
| #include <init.h> | ||
|
|
@@ -38,6 +39,7 @@ | |
| #include <llmq/chainlocks.h> | ||
| #include <llmq/instantsend.h> | ||
|
|
||
| #include <numeric> | ||
| #include <stdint.h> | ||
|
|
||
| #include <univalue.h> | ||
|
|
@@ -1392,6 +1394,141 @@ UniValue converttopsbt(const JSONRPCRequest& request) | |
| return EncodeBase64(ssTx.str()); | ||
| } | ||
|
|
||
| UniValue utxoupdatepsbt(const JSONRPCRequest& request) | ||
| { | ||
| if (request.fHelp || request.params.size() != 1) { | ||
| throw std::runtime_error( | ||
| RPCHelpMan{"utxoupdatepsbt", | ||
| "\nUpdates a PSBT with UTXOs retrieved from the UTXO set or the mempool.\n", | ||
| { | ||
| {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} | ||
| }, | ||
| RPCResult { | ||
| " \"psbt\" (string) The base64-encoded partially signed transaction with inputs updated\n" | ||
| }, | ||
| RPCExamples { | ||
| HelpExampleCli("utxoupdatepsbt", "\"psbt\"") | ||
| }}.ToString()); | ||
| } | ||
|
|
||
| RPCTypeCheck(request.params, {UniValue::VSTR}, true); | ||
|
|
||
| // Unserialize the transactions | ||
| PartiallySignedTransaction psbtx; | ||
| std::string error; | ||
| if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | ||
| throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); | ||
| } | ||
|
|
||
| // Fetch previous transactions (inputs): | ||
| CCoinsView viewDummy; | ||
| CCoinsViewCache view(&viewDummy); | ||
| { | ||
| LOCK2(cs_main, mempool.cs); | ||
| CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); | ||
| CCoinsViewMemPool viewMempool(&viewChain, mempool); | ||
| view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view | ||
|
|
||
| for (const CTxIn& txin : psbtx.tx->vin) { | ||
| view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail. | ||
| } | ||
|
|
||
| view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long | ||
| } | ||
|
|
||
| // Fill the inputs | ||
| for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { | ||
| PSBTInput& input = psbtx.inputs.at(i); | ||
|
|
||
| if (input.non_witness_utxo) { | ||
| continue; | ||
| } | ||
|
||
|
|
||
| const Coin& coin = view.AccessCoin(psbtx.tx->vin[i].prevout); | ||
|
|
||
| std::vector<std::vector<unsigned char>> solutions_data; | ||
| Solver(coin.out.scriptPubKey, solutions_data); | ||
| } | ||
|
|
||
| CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||
| ssTx << psbtx; | ||
| return EncodeBase64(ssTx.str()); | ||
| } | ||
|
|
||
| UniValue joinpsbts(const JSONRPCRequest& request) | ||
| { | ||
| if (request.fHelp || request.params.size() != 1) { | ||
| throw std::runtime_error( | ||
| RPCHelpMan{"joinpsbts", | ||
| "\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n" | ||
| "No input in any of the PSBTs can be in more than one of the PSBTs.\n", | ||
| { | ||
| {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of base64 strings of partially signed transactions", | ||
| { | ||
| {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} | ||
| }} | ||
| }, | ||
| RPCResult { | ||
| " \"psbt\" (string) The base64-encoded partially signed transaction\n" | ||
| }, | ||
| RPCExamples { | ||
| HelpExampleCli("joinpsbts", "\"psbt\"") | ||
| }}.ToString()); | ||
| } | ||
|
|
||
| RPCTypeCheck(request.params, {UniValue::VARR}, true); | ||
|
|
||
| // Unserialize the transactions | ||
| std::vector<PartiallySignedTransaction> psbtxs; | ||
| UniValue txs = request.params[0].get_array(); | ||
|
|
||
| if (txs.size() <= 1) { | ||
| throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs."); | ||
| } | ||
|
|
||
| int32_t best_version = 1; | ||
| uint32_t best_locktime = 0xffffffff; | ||
| for (unsigned int i = 0; i < txs.size(); ++i) { | ||
| PartiallySignedTransaction psbtx; | ||
| std::string error; | ||
| if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) { | ||
| throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); | ||
| } | ||
| psbtxs.push_back(psbtx); | ||
| // Choose the highest version number | ||
| if (psbtx.tx->nVersion > best_version) { | ||
| best_version = psbtx.tx->nVersion; | ||
| } | ||
| // Choose the lowest lock time | ||
| if (psbtx.tx->nLockTime < best_locktime) { | ||
| best_locktime = psbtx.tx->nLockTime; | ||
| } | ||
| } | ||
|
|
||
| // Create a blank psbt where everything will be added | ||
| PartiallySignedTransaction merged_psbt; | ||
| merged_psbt.tx = CMutableTransaction(); | ||
| merged_psbt.tx->nVersion = best_version; | ||
| merged_psbt.tx->nLockTime = best_locktime; | ||
|
|
||
| // Merge | ||
| for (auto& psbt : psbtxs) { | ||
| for (unsigned int i = 0; i < psbt.tx->vin.size(); ++i) { | ||
| if (!merged_psbt.AddInput(psbt.tx->vin[i], psbt.inputs[i])) { | ||
| throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input %s:%d exists in multiple PSBTs", psbt.tx->vin[i].prevout.hash.ToString().c_str(), psbt.tx->vin[i].prevout.n)); | ||
| } | ||
| } | ||
| for (unsigned int i = 0; i < psbt.tx->vout.size(); ++i) { | ||
| merged_psbt.AddOutput(psbt.tx->vout[i], psbt.outputs[i]); | ||
| } | ||
| merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); | ||
| } | ||
|
|
||
| CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||
| ssTx << merged_psbt; | ||
| return EncodeBase64(ssTx.str()); | ||
| } | ||
|
|
||
| // clang-format off | ||
| static const CRPCCommand commands[] = | ||
| { // category name actor (function) argNames | ||
|
|
@@ -1409,6 +1546,8 @@ static const CRPCCommand commands[] = | |
| { "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} }, | ||
| { "rawtransactions", "createpsbt", &createpsbt, {"inputs","outputs","locktime"} }, | ||
| { "rawtransactions", "converttopsbt", &converttopsbt, {"hexstring","permitsigdata"} }, | ||
| { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt"} }, | ||
| { "rawtransactions", "joinpsbts", &joinpsbts, {"txs"} }, | ||
|
|
||
| { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, | ||
| { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.