mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
merge bitcoin#15638: Pull wallet code out of libbitcoin_server (#4560)
* merge 15638: Move CheckTransaction from lib_server to lib_consensus * merge 15638: Move policy settings to new src/policy/settings unit * merge 15638: Move rpc utility methods to rpc/util * merge 15638: Move rpc rawtransaction util functions to rpc/rawtransaction_util.cpp * merge 15638: Move several units into common libraries * merge 15638: Move wallet load functions to wallet/load unit * merge 15638: Document src subdirectories and different libraries * [build] Add several util units (cleanup) * build: resolve missing declarations by re-specifying headers
This commit is contained in:
parent
a3a8bfee08
commit
d978259654
@ -158,6 +158,7 @@ BITCOIN_CORE_H = \
|
||||
compat/sanity.h \
|
||||
compressor.h \
|
||||
consensus/consensus.h \
|
||||
consensus/tx_check.h \
|
||||
consensus/tx_verify.h \
|
||||
core_io.h \
|
||||
core_memusage.h \
|
||||
@ -241,6 +242,7 @@ BITCOIN_CORE_H = \
|
||||
policy/feerate.h \
|
||||
policy/fees.h \
|
||||
policy/policy.h \
|
||||
policy/settings.h \
|
||||
pow.h \
|
||||
protocol.h \
|
||||
psbt.h \
|
||||
@ -251,7 +253,7 @@ BITCOIN_CORE_H = \
|
||||
rpc/mining.h \
|
||||
rpc/protocol.h \
|
||||
rpc/server.h \
|
||||
rpc/rawtransaction.h \
|
||||
rpc/rawtransaction_util.h \
|
||||
rpc/register.h \
|
||||
rpc/util.h \
|
||||
saltedhasher.h \
|
||||
@ -309,6 +311,7 @@ BITCOIN_CORE_H = \
|
||||
wallet/crypter.h \
|
||||
wallet/db.h \
|
||||
wallet/fees.h \
|
||||
wallet/load.h \
|
||||
wallet/psbtwallet.h \
|
||||
wallet/rpcwallet.h \
|
||||
wallet/wallet.h \
|
||||
@ -331,6 +334,9 @@ obj/build.h: FORCE
|
||||
libdash_util_a-clientversion.$(OBJEXT): obj/build.h
|
||||
|
||||
# server: shared between dashd and dash-qt
|
||||
# Contains code accessing mempool and chain state that is meant to be separated
|
||||
# from wallet and gui code (see node/README.md). Shared code should go in
|
||||
# libdash_common or libdash_util libraries, instead.
|
||||
libdash_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
|
||||
libdash_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libdash_server_a_SOURCES = \
|
||||
@ -338,7 +344,6 @@ libdash_server_a_SOURCES = \
|
||||
addrman.cpp \
|
||||
banman.cpp \
|
||||
batchedlogger.cpp \
|
||||
bloom.cpp \
|
||||
blockencodings.cpp \
|
||||
blockfilter.cpp \
|
||||
chain.cpp \
|
||||
@ -361,7 +366,6 @@ libdash_server_a_SOURCES = \
|
||||
index/blockfilterindex.cpp \
|
||||
index/txindex.cpp \
|
||||
interfaces/chain.cpp \
|
||||
interfaces/handler.cpp \
|
||||
interfaces/node.cpp \
|
||||
init.cpp \
|
||||
dbwrapper.cpp \
|
||||
@ -389,7 +393,6 @@ libdash_server_a_SOURCES = \
|
||||
masternode/payments.cpp \
|
||||
masternode/sync.cpp \
|
||||
masternode/utils.cpp \
|
||||
merkleblock.cpp \
|
||||
messagesigner.cpp \
|
||||
miner.cpp \
|
||||
net.cpp \
|
||||
@ -401,6 +404,7 @@ libdash_server_a_SOURCES = \
|
||||
noui.cpp \
|
||||
policy/fees.cpp \
|
||||
policy/policy.cpp \
|
||||
policy/settings.cpp \
|
||||
pow.cpp \
|
||||
rest.cpp \
|
||||
rpc/blockchain.cpp \
|
||||
@ -414,7 +418,6 @@ libdash_server_a_SOURCES = \
|
||||
rpc/rpcquorums.cpp \
|
||||
rpc/server.cpp \
|
||||
rpc/coinjoin.cpp \
|
||||
rpc/util.cpp \
|
||||
script/sigcache.cpp \
|
||||
shutdown.cpp \
|
||||
spork.cpp \
|
||||
@ -462,7 +465,7 @@ libdash_wallet_a_SOURCES = \
|
||||
wallet/crypter.cpp \
|
||||
wallet/db.cpp \
|
||||
wallet/fees.cpp \
|
||||
wallet/init.cpp \
|
||||
wallet/load.cpp \
|
||||
wallet/psbtwallet.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
@ -571,6 +574,7 @@ libdash_consensus_a_SOURCES = \
|
||||
consensus/merkle.cpp \
|
||||
consensus/merkle.h \
|
||||
consensus/params.h \
|
||||
consensus/tx_check.cpp \
|
||||
consensus/validation.h \
|
||||
hash.cpp \
|
||||
hash.h \
|
||||
@ -605,6 +609,7 @@ libdash_common_a_SOURCES = \
|
||||
base58.cpp \
|
||||
bech32.cpp \
|
||||
bip39.cpp \
|
||||
bloom.cpp \
|
||||
chainparams.cpp \
|
||||
coins.cpp \
|
||||
compressor.cpp \
|
||||
@ -614,12 +619,16 @@ libdash_common_a_SOURCES = \
|
||||
key.cpp \
|
||||
key_io.cpp \
|
||||
keystore.cpp \
|
||||
merkleblock.cpp \
|
||||
netaddress.cpp \
|
||||
netbase.cpp \
|
||||
net_permissions.cpp \
|
||||
policy/feerate.cpp \
|
||||
policy/policy.cpp \
|
||||
psbt.cpp \
|
||||
protocol.cpp \
|
||||
rpc/rawtransaction_util.cpp \
|
||||
rpc/util.cpp \
|
||||
saltedhasher.cpp \
|
||||
scheduler.cpp \
|
||||
script/descriptor.cpp \
|
||||
@ -648,6 +657,7 @@ libdash_util_a_SOURCES = \
|
||||
compat/glibcxx_sanity.cpp \
|
||||
compat/strnlen.cpp \
|
||||
fs.cpp \
|
||||
interfaces/handler.cpp \
|
||||
logging.cpp \
|
||||
random.cpp \
|
||||
rpc/protocol.cpp \
|
||||
|
65
src/consensus/tx_check.cpp
Normal file
65
src/consensus/tx_check.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2017-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <version.h>
|
||||
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/tx_check.h>
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <consensus/validation.h>
|
||||
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
||||
{
|
||||
bool allowEmptyTxInOut = false;
|
||||
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||
allowEmptyTxInOut = true;
|
||||
}
|
||||
|
||||
// Basic checks that don't depend on any context
|
||||
if (!allowEmptyTxInOut && tx.vin.empty())
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
|
||||
if (!allowEmptyTxInOut && tx.vout.empty())
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
|
||||
// Size limits
|
||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
|
||||
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-payload-oversize");
|
||||
|
||||
// Check for negative or overflow output values
|
||||
CAmount nValueOut = 0;
|
||||
for (const auto& txout : tx.vout) {
|
||||
if (txout.nValue < 0)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
|
||||
if (txout.nValue > MAX_MONEY)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
|
||||
nValueOut += txout.nValue;
|
||||
if (!MoneyRange(nValueOut))
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||
}
|
||||
|
||||
// Check for duplicate inputs
|
||||
std::set<COutPoint> vInOutPoints;
|
||||
for (const auto& txin : tx.vin) {
|
||||
if (!vInOutPoints.insert(txin.prevout).second)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
||||
}
|
||||
|
||||
if (tx.IsCoinBase()) {
|
||||
size_t minCbSize = 2;
|
||||
if (tx.nType == TRANSACTION_COINBASE) {
|
||||
// With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height
|
||||
minCbSize = 1;
|
||||
}
|
||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
|
||||
} else {
|
||||
for (const auto& txin : tx.vin)
|
||||
if (txin.prevout.IsNull())
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
21
src/consensus/tx_check.h
Normal file
21
src/consensus/tx_check.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2017-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CONSENSUS_TX_CHECK_H
|
||||
#define BITCOIN_CONSENSUS_TX_CHECK_H
|
||||
|
||||
/**
|
||||
* Context-independent transaction checking code that can be called outside the
|
||||
* bitcoin server and doesn't depend on chain or mempool state. Transaction
|
||||
* verification code that does call server functions or depend on server state
|
||||
* belongs in tx_verify.h/cpp instead.
|
||||
*/
|
||||
|
||||
class CTransaction;
|
||||
class CValidationState;
|
||||
|
||||
/** Context-independent validity checks */
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||
|
||||
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
|
@ -159,65 +159,6 @@ unsigned int GetTransactionSigOpCount(const CTransaction& tx, const CCoinsViewCa
|
||||
return nSigOps;
|
||||
}
|
||||
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||
{
|
||||
bool allowEmptyTxInOut = false;
|
||||
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
|
||||
allowEmptyTxInOut = true;
|
||||
}
|
||||
|
||||
// Basic checks that don't depend on any context
|
||||
if (!allowEmptyTxInOut && tx.vin.empty())
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
|
||||
if (!allowEmptyTxInOut && tx.vout.empty())
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
|
||||
// Size limits
|
||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
|
||||
if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-payload-oversize");
|
||||
|
||||
// Check for negative or overflow output values
|
||||
CAmount nValueOut = 0;
|
||||
for (const auto& txout : tx.vout)
|
||||
{
|
||||
if (txout.nValue < 0)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
|
||||
if (txout.nValue > MAX_MONEY)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
|
||||
nValueOut += txout.nValue;
|
||||
if (!MoneyRange(nValueOut))
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||
}
|
||||
|
||||
// Check for duplicate inputs
|
||||
std::set<COutPoint> vInOutPoints;
|
||||
for (const auto& txin : tx.vin)
|
||||
{
|
||||
if (!vInOutPoints.insert(txin.prevout).second)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
||||
}
|
||||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
size_t minCbSize = 2;
|
||||
if (tx.nType == TRANSACTION_COINBASE) {
|
||||
// With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height
|
||||
minCbSize = 1;
|
||||
}
|
||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& txin : tx.vin)
|
||||
if (txin.prevout.IsNull())
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
|
||||
{
|
||||
// are the actual inputs available?
|
||||
|
@ -17,9 +17,6 @@ class CValidationState;
|
||||
|
||||
/** Transaction validation functions */
|
||||
|
||||
/** Context-independent validity checks */
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||
|
||||
namespace Consensus {
|
||||
/**
|
||||
* Check whether all inputs of this transaction are valid (no double spends and amounts)
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <policy/feerate.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/register.h>
|
||||
#include <rpc/blockchain.h>
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <rpc/protocol.h>
|
||||
#include <rpc/server.h>
|
||||
#include <shutdown.h>
|
||||
#include <policy/settings.h>
|
||||
#include <sync.h>
|
||||
#include <threadsafety.h>
|
||||
#include <timedata.h>
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <policy/feerate.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <primitives/block.h>
|
||||
#include <rpc/server.h>
|
||||
#include <scheduler.h>
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <validation.h>
|
||||
#include <wallet/fees.h>
|
||||
#include <wallet/rpcwallet.h>
|
||||
#include <wallet/load.h>
|
||||
#include <wallet/wallet.h>
|
||||
#include <wallet/walletutil.h>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <key_io.h>
|
||||
#include <hash.h>
|
||||
#include <validation.h> // For strMessageMagic
|
||||
#include <util/validation.h> // For strMessageMagic
|
||||
#include <messagesigner.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/strencodings.h>
|
||||
|
22
src/node/README.md
Normal file
22
src/node/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# src/node/
|
||||
|
||||
The [`src/node/`](./) directory contains code that needs to access node state
|
||||
(state in `CChain`, `CBlockIndex`, `CCoinsView`, `CTxMemPool`, and similar
|
||||
classes).
|
||||
|
||||
Code in [`src/node/`](./) is meant to be segregated from code in
|
||||
[`src/wallet/`](../wallet/) and [`src/qt/`](../qt/), to ensure wallet and GUI
|
||||
code changes don't interfere with node operation, to allow wallet and GUI code
|
||||
to run in separate processes, and to perhaps eventually allow wallet and GUI
|
||||
code to be maintained in separate source repositories.
|
||||
|
||||
As a rule of thumb, code in one of the [`src/node/`](./),
|
||||
[`src/wallet/`](../wallet/), or [`src/qt/`](../qt/) directories should avoid
|
||||
calling code in the other directories directly, and only invoke it indirectly
|
||||
through the more limited [`src/interfaces/`](../interfaces/) classes.
|
||||
|
||||
The [`src/node/`](./) directory is a new directory introduced in
|
||||
[#14978](https://github.com/bitcoin/bitcoin/pull/14978) and at the moment is
|
||||
sparsely populated. Eventually more substantial files like
|
||||
[`src/validation.cpp`](../validation.cpp) and
|
||||
[`src/txmempool.cpp`](../txmempool.cpp) might be moved there.
|
@ -13,32 +13,6 @@
|
||||
|
||||
#include <future>
|
||||
|
||||
std::string TransactionErrorString(const TransactionError err)
|
||||
{
|
||||
switch (err) {
|
||||
case TransactionError::OK:
|
||||
return "No error";
|
||||
case TransactionError::MISSING_INPUTS:
|
||||
return "Missing inputs";
|
||||
case TransactionError::ALREADY_IN_CHAIN:
|
||||
return "Transaction already in block chain";
|
||||
case TransactionError::P2P_DISABLED:
|
||||
return "Peer-to-peer functionality missing or disabled";
|
||||
case TransactionError::MEMPOOL_REJECTED:
|
||||
return "Transaction rejected by AcceptToMemoryPool";
|
||||
case TransactionError::MEMPOOL_ERROR:
|
||||
return "AcceptToMemoryPool failed";
|
||||
case TransactionError::INVALID_PSBT:
|
||||
return "PSBT is not sane";
|
||||
case TransactionError::PSBT_MISMATCH:
|
||||
return "PSBTs not compatible (different transactions)";
|
||||
case TransactionError::SIGHASH_MISMATCH:
|
||||
return "Specified sighash value does not match existing value";
|
||||
// no default case, so the compiler can warn about missing cases
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& highfee, const bool bypass_limits)
|
||||
{
|
||||
std::promise<void> promise;
|
||||
|
@ -8,20 +8,7 @@
|
||||
#include <attributes.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <uint256.h>
|
||||
|
||||
enum class TransactionError {
|
||||
OK, //!< No error
|
||||
MISSING_INPUTS,
|
||||
ALREADY_IN_CHAIN,
|
||||
P2P_DISABLED,
|
||||
MEMPOOL_REJECTED,
|
||||
MEMPOOL_ERROR,
|
||||
INVALID_PSBT,
|
||||
PSBT_MISMATCH,
|
||||
SIGHASH_MISMATCH,
|
||||
};
|
||||
|
||||
std::string TransactionErrorString(const TransactionError error);
|
||||
#include <util/error.h>
|
||||
|
||||
/**
|
||||
* Broadcast a transaction
|
||||
|
@ -26,41 +26,6 @@ std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
|
||||
|
||||
return horizon_string->second;
|
||||
}
|
||||
|
||||
std::string StringForFeeReason(FeeReason reason) {
|
||||
static const std::map<FeeReason, std::string> fee_reason_strings = {
|
||||
{FeeReason::NONE, "None"},
|
||||
{FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
|
||||
{FeeReason::FULL_ESTIMATE, "Target 85% Threshold"},
|
||||
{FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"},
|
||||
{FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"},
|
||||
{FeeReason::MEMPOOL_MIN, "Mempool Min Fee"},
|
||||
{FeeReason::PAYTXFEE, "PayTxFee set"},
|
||||
{FeeReason::FALLBACK, "Fallback fee"},
|
||||
{FeeReason::REQUIRED, "Minimum Required Fee"},
|
||||
{FeeReason::MAXTXFEE, "MaxTxFee limit"}
|
||||
};
|
||||
auto reason_string = fee_reason_strings.find(reason);
|
||||
|
||||
if (reason_string == fee_reason_strings.end()) return "Unknown";
|
||||
|
||||
return reason_string->second;
|
||||
}
|
||||
|
||||
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
|
||||
static const std::map<std::string, FeeEstimateMode> fee_modes = {
|
||||
{"UNSET", FeeEstimateMode::UNSET},
|
||||
{"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
|
||||
{"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
|
||||
};
|
||||
auto mode = fee_modes.find(mode_string);
|
||||
|
||||
if (mode == fee_modes.end()) return false;
|
||||
|
||||
fee_estimate_mode = mode->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* We will instantiate an instance of this class to track transactions that were
|
||||
* included in a block. We will lump transactions into a bucket according to their
|
||||
|
@ -46,8 +46,6 @@ enum class FeeReason {
|
||||
MAXTXFEE,
|
||||
};
|
||||
|
||||
std::string StringForFeeReason(FeeReason reason);
|
||||
|
||||
/* Used to determine type of fee estimation requested */
|
||||
enum class FeeEstimateMode {
|
||||
UNSET, //!< Use default settings based on other criteria
|
||||
@ -55,8 +53,6 @@ enum class FeeEstimateMode {
|
||||
CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
|
||||
};
|
||||
|
||||
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
|
||||
|
||||
/* Used to return detailed information about a feerate bucket */
|
||||
struct EstimatorBucket
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <validation.h>
|
||||
#include <coins.h>
|
||||
#include <policy/settings.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -170,10 +171,6 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
|
||||
CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
|
||||
CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
|
||||
|
||||
int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigOp)
|
||||
{
|
||||
return std::max(nSize, nSigOp * nBytesPerSigOp);
|
||||
|
@ -34,6 +34,8 @@ static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
|
||||
static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
|
||||
/** Default for -bytespersigop */
|
||||
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
|
||||
/** Default for -permitbaremultisig */
|
||||
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
|
||||
/** Min feerate for defining dust. Historically this has been based on the
|
||||
* minRelayTxFee, however changing the dust limit changes which transactions are
|
||||
* standard and should be done with care and ideally rarely. It makes sense to
|
||||
@ -83,12 +85,8 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason);
|
||||
*/
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
||||
|
||||
extern unsigned int nBytesPerSigOp;
|
||||
|
||||
/** Compute the virtual transaction size (taking sigops into account). */
|
||||
int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigOp);
|
||||
int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOp = 0);
|
||||
|
||||
extern CFeeRate incrementalRelayFee;
|
||||
extern CFeeRate dustRelayFee;
|
||||
#endif // BITCOIN_POLICY_POLICY_H
|
||||
|
14
src/policy/settings.cpp
Normal file
14
src/policy/settings.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <policy/settings.h>
|
||||
|
||||
#include <policy/feerate.h>
|
||||
#include <policy/policy.h>
|
||||
|
||||
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
|
||||
CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
|
||||
CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
|
||||
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
|
17
src/policy/settings.h
Normal file
17
src/policy/settings.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_POLICY_SETTINGS_H
|
||||
#define BITCOIN_POLICY_SETTINGS_H
|
||||
|
||||
class CFeeRate;
|
||||
|
||||
// Policy settings which are configurable at runtime.
|
||||
extern CFeeRate incrementalRelayFee;
|
||||
extern CFeeRate dustRelayFee;
|
||||
extern unsigned int nBytesPerSigOp;
|
||||
extern bool fIsBareMultisigStd;
|
||||
|
||||
#endif // BITCOIN_POLICY_SETTINGS_H
|
@ -14,6 +14,7 @@
|
||||
#include <net_permissions.h>
|
||||
#include <netbase.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <rpc/protocol.h>
|
||||
#include <rpc/util.h>
|
||||
#include <sync.h>
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <policy/policy.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <psbt.h>
|
||||
#include <rpc/rawtransaction.h>
|
||||
#include <rpc/rawtransaction_util.h>
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/script.h>
|
||||
@ -397,96 +397,6 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
|
||||
return res;
|
||||
}
|
||||
|
||||
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime)
|
||||
{
|
||||
if (inputs_in.isNull() || outputs_in.isNull())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
|
||||
|
||||
UniValue inputs = inputs_in.get_array();
|
||||
const bool outputs_is_obj = outputs_in.isObject();
|
||||
UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
|
||||
|
||||
CMutableTransaction rawTx;
|
||||
if (!locktime.isNull()) {
|
||||
int64_t nLockTime = locktime.get_int64();
|
||||
if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
|
||||
rawTx.nLockTime = nLockTime;
|
||||
}
|
||||
|
||||
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
|
||||
const UniValue& input = inputs[idx];
|
||||
const UniValue& o = input.get_obj();
|
||||
|
||||
uint256 txid = ParseHashO(o, "txid");
|
||||
|
||||
const UniValue& vout_v = find_value(o, "vout");
|
||||
if (!vout_v.isNum())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
|
||||
int nOutput = vout_v.get_int();
|
||||
if (nOutput < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
|
||||
|
||||
uint32_t nSequence = (rawTx.nLockTime ? CTxIn::SEQUENCE_FINAL - 1 : CTxIn::SEQUENCE_FINAL);
|
||||
|
||||
// set the sequence number if passed in the parameters object
|
||||
const UniValue& sequenceObj = find_value(o, "sequence");
|
||||
if (sequenceObj.isNum()) {
|
||||
int64_t seqNr64 = sequenceObj.get_int64();
|
||||
if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
|
||||
else
|
||||
nSequence = (uint32_t)seqNr64;
|
||||
}
|
||||
|
||||
CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
|
||||
|
||||
rawTx.vin.push_back(in);
|
||||
}
|
||||
|
||||
std::set<CTxDestination> destinations;
|
||||
if (!outputs_is_obj) {
|
||||
// Translate array of key-value pairs into dict
|
||||
UniValue outputs_dict = UniValue(UniValue::VOBJ);
|
||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
||||
const UniValue& output = outputs[i];
|
||||
if (!output.isObject()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
|
||||
}
|
||||
if (output.size() != 1) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
|
||||
}
|
||||
outputs_dict.pushKVs(output);
|
||||
}
|
||||
outputs = std::move(outputs_dict);
|
||||
}
|
||||
for (const std::string& name_ : outputs.getKeys()) {
|
||||
if (name_ == "data") {
|
||||
std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
|
||||
|
||||
CTxOut out(0, CScript() << OP_RETURN << data);
|
||||
rawTx.vout.push_back(out);
|
||||
} else {
|
||||
CTxDestination destination = DecodeDestination(name_);
|
||||
if (!IsValidDestination(destination)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + name_);
|
||||
}
|
||||
|
||||
if (!destinations.insert(destination).second) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
|
||||
}
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(destination);
|
||||
CAmount nAmount = AmountFromValue(outputs[name_]);
|
||||
|
||||
CTxOut out(nAmount, scriptPubKey);
|
||||
rawTx.vout.push_back(out);
|
||||
}
|
||||
}
|
||||
|
||||
return rawTx;
|
||||
}
|
||||
|
||||
static UniValue createrawtransaction(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
|
||||
@ -673,18 +583,6 @@ static UniValue decodescript(const JSONRPCRequest& request)
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
|
||||
static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
|
||||
{
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
entry.pushKV("txid", txin.prevout.hash.ToString());
|
||||
entry.pushKV("vout", (uint64_t)txin.prevout.n);
|
||||
entry.pushKV("scriptSig", HexStr(txin.scriptSig));
|
||||
entry.pushKV("sequence", (uint64_t)txin.nSequence);
|
||||
entry.pushKV("error", strMessage);
|
||||
vErrorsRet.push_back(entry);
|
||||
}
|
||||
|
||||
static UniValue combinerawtransaction(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 1)
|
||||
@ -769,135 +667,6 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
|
||||
return EncodeHexTx(CTransaction(mergedTx));
|
||||
}
|
||||
|
||||
// TODO(https://github.com/bitcoin/bitcoin/pull/10973#discussion_r267084237):
|
||||
// This function is called from both wallet and node rpcs
|
||||
// (signrawtransactionwithwallet and signrawtransactionwithkey). It should be
|
||||
// moved to a util file so wallet code doesn't need to link against node code.
|
||||
// Also the dependency on interfaces::Chain should be removed, so
|
||||
// signrawtransactionwithkey doesn't need access to a Chain instance.
|
||||
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
|
||||
{
|
||||
// Fetch previous transactions (inputs):
|
||||
std::map<COutPoint, Coin> coins;
|
||||
for (const CTxIn& txin : mtx.vin) {
|
||||
coins[txin.prevout]; // Create empty map entry keyed by prevout.
|
||||
}
|
||||
chain.findCoins(coins);
|
||||
|
||||
// Add previous txouts given in the RPC call:
|
||||
if (!prevTxsUnival.isNull()) {
|
||||
UniValue prevTxs = prevTxsUnival.get_array();
|
||||
for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) {
|
||||
const UniValue& p = prevTxs[idx];
|
||||
if (!p.isObject()) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
|
||||
}
|
||||
|
||||
UniValue prevOut = p.get_obj();
|
||||
|
||||
RPCTypeCheckObj(prevOut,
|
||||
{
|
||||
{"txid", UniValueType(UniValue::VSTR)},
|
||||
{"vout", UniValueType(UniValue::VNUM)},
|
||||
{"scriptPubKey", UniValueType(UniValue::VSTR)},
|
||||
});
|
||||
|
||||
uint256 txid = ParseHashO(prevOut, "txid");
|
||||
|
||||
int nOut = find_value(prevOut, "vout").get_int();
|
||||
if (nOut < 0) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
|
||||
}
|
||||
|
||||
COutPoint out(txid, nOut);
|
||||
std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
|
||||
CScript scriptPubKey(pkData.begin(), pkData.end());
|
||||
|
||||
{
|
||||
auto coin = coins.find(out);
|
||||
if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
|
||||
std::string err("Previous output scriptPubKey mismatch:\n");
|
||||
err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
|
||||
ScriptToAsmStr(scriptPubKey);
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
|
||||
}
|
||||
Coin newcoin;
|
||||
newcoin.out.scriptPubKey = scriptPubKey;
|
||||
newcoin.out.nValue = 0;
|
||||
if (prevOut.exists("amount")) {
|
||||
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
|
||||
}
|
||||
newcoin.nHeight = 1;
|
||||
coins[out] = std::move(newcoin);
|
||||
}
|
||||
|
||||
// if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
|
||||
if (is_temp_keystore && scriptPubKey.IsPayToScriptHash()) {
|
||||
RPCTypeCheckObj(prevOut,
|
||||
{
|
||||
{"redeemScript", UniValueType(UniValue::VSTR)},
|
||||
});
|
||||
UniValue v = find_value(prevOut, "redeemScript");
|
||||
if (!v.isNull()) {
|
||||
std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
|
||||
CScript redeemScript(rsData.begin(), rsData.end());
|
||||
keystore->AddCScript(redeemScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nHashType = ParseSighashString(hashType);
|
||||
|
||||
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
|
||||
|
||||
// Script verification errors
|
||||
UniValue vErrors(UniValue::VARR);
|
||||
|
||||
// Use CTransaction for the constant parts of the
|
||||
// transaction to avoid rehashing.
|
||||
const CTransaction txConst(mtx);
|
||||
// Sign what we can:
|
||||
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
|
||||
CTxIn& txin = mtx.vin[i];
|
||||
auto coin = coins.find(txin.prevout);
|
||||
if (coin == coins.end() || coin->second.IsSpent()) {
|
||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
||||
continue;
|
||||
}
|
||||
const CScript& prevPubKey = coin->second.out.scriptPubKey;
|
||||
const CAmount& amount = coin->second.out.nValue;
|
||||
|
||||
SignatureData sigdata = DataFromTransaction(mtx, i, coin->second.out);
|
||||
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||
if (!fHashSingle || (i < mtx.vout.size())) {
|
||||
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
|
||||
}
|
||||
|
||||
UpdateInput(txin, sigdata);
|
||||
|
||||
ScriptError serror = SCRIPT_ERR_OK;
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
|
||||
if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
|
||||
// Unable to sign input and verification failed (possible attempt to partially sign).
|
||||
TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
|
||||
} else {
|
||||
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
|
||||
}
|
||||
}
|
||||
}
|
||||
bool fComplete = vErrors.empty();
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
|
||||
result.pushKV("complete", fComplete);
|
||||
if (!vErrors.empty()) {
|
||||
result.pushKV("errors", vErrors);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
|
||||
|
250
src/rpc/rawtransaction_util.cpp
Normal file
250
src/rpc/rawtransaction_util.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// 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.
|
||||
|
||||
#include <rpc/rawtransaction_util.h>
|
||||
|
||||
#include <coins.h>
|
||||
#include <core_io.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <rpc/protocol.h>
|
||||
#include <rpc/util.h>
|
||||
#include <tinyformat.h>
|
||||
#include <univalue.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <validation.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime)
|
||||
{
|
||||
if (inputs_in.isNull() || outputs_in.isNull())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
|
||||
|
||||
UniValue inputs = inputs_in.get_array();
|
||||
const bool outputs_is_obj = outputs_in.isObject();
|
||||
UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
|
||||
|
||||
CMutableTransaction rawTx;
|
||||
if (!locktime.isNull()) {
|
||||
int64_t nLockTime = locktime.get_int64();
|
||||
if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
|
||||
rawTx.nLockTime = nLockTime;
|
||||
}
|
||||
|
||||
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
|
||||
const UniValue& input = inputs[idx];
|
||||
const UniValue& o = input.get_obj();
|
||||
|
||||
uint256 txid = ParseHashO(o, "txid");
|
||||
|
||||
const UniValue& vout_v = find_value(o, "vout");
|
||||
if (!vout_v.isNum())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
|
||||
int nOutput = vout_v.get_int();
|
||||
if (nOutput < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
|
||||
|
||||
uint32_t nSequence = (rawTx.nLockTime ? CTxIn::SEQUENCE_FINAL - 1 : CTxIn::SEQUENCE_FINAL);
|
||||
|
||||
// set the sequence number if passed in the parameters object
|
||||
const UniValue& sequenceObj = find_value(o, "sequence");
|
||||
if (sequenceObj.isNum()) {
|
||||
int64_t seqNr64 = sequenceObj.get_int64();
|
||||
if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
|
||||
else
|
||||
nSequence = (uint32_t)seqNr64;
|
||||
}
|
||||
|
||||
CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
|
||||
|
||||
rawTx.vin.push_back(in);
|
||||
}
|
||||
|
||||
std::set<CTxDestination> destinations;
|
||||
if (!outputs_is_obj) {
|
||||
// Translate array of key-value pairs into dict
|
||||
UniValue outputs_dict = UniValue(UniValue::VOBJ);
|
||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
||||
const UniValue& output = outputs[i];
|
||||
if (!output.isObject()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
|
||||
}
|
||||
if (output.size() != 1) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
|
||||
}
|
||||
outputs_dict.pushKVs(output);
|
||||
}
|
||||
outputs = std::move(outputs_dict);
|
||||
}
|
||||
for (const std::string& name_ : outputs.getKeys()) {
|
||||
if (name_ == "data") {
|
||||
std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
|
||||
|
||||
CTxOut out(0, CScript() << OP_RETURN << data);
|
||||
rawTx.vout.push_back(out);
|
||||
} else {
|
||||
CTxDestination destination = DecodeDestination(name_);
|
||||
if (!IsValidDestination(destination)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + name_);
|
||||
}
|
||||
|
||||
if (!destinations.insert(destination).second) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
|
||||
}
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(destination);
|
||||
CAmount nAmount = AmountFromValue(outputs[name_]);
|
||||
|
||||
CTxOut out(nAmount, scriptPubKey);
|
||||
rawTx.vout.push_back(out);
|
||||
}
|
||||
}
|
||||
|
||||
return rawTx;
|
||||
}
|
||||
|
||||
/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
|
||||
static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
|
||||
{
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
entry.pushKV("txid", txin.prevout.hash.ToString());
|
||||
entry.pushKV("vout", (uint64_t)txin.prevout.n);
|
||||
entry.pushKV("scriptSig", HexStr(txin.scriptSig));
|
||||
entry.pushKV("sequence", (uint64_t)txin.nSequence);
|
||||
entry.pushKV("error", strMessage);
|
||||
vErrorsRet.push_back(entry);
|
||||
}
|
||||
|
||||
// TODO(https://github.com/bitcoin/bitcoin/pull/10973#discussion_r267084237):
|
||||
// The dependency on interfaces::Chain should be removed, so
|
||||
// signrawtransactionwithkey doesn't need access to a Chain instance.
|
||||
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
|
||||
{
|
||||
// Fetch previous transactions (inputs):
|
||||
std::map<COutPoint, Coin> coins;
|
||||
for (const CTxIn& txin : mtx.vin) {
|
||||
coins[txin.prevout]; // Create empty map entry keyed by prevout.
|
||||
}
|
||||
chain.findCoins(coins);
|
||||
|
||||
// Add previous txouts given in the RPC call:
|
||||
if (!prevTxsUnival.isNull()) {
|
||||
UniValue prevTxs = prevTxsUnival.get_array();
|
||||
for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) {
|
||||
const UniValue& p = prevTxs[idx];
|
||||
if (!p.isObject()) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
|
||||
}
|
||||
|
||||
UniValue prevOut = p.get_obj();
|
||||
|
||||
RPCTypeCheckObj(prevOut,
|
||||
{
|
||||
{"txid", UniValueType(UniValue::VSTR)},
|
||||
{"vout", UniValueType(UniValue::VNUM)},
|
||||
{"scriptPubKey", UniValueType(UniValue::VSTR)},
|
||||
});
|
||||
|
||||
uint256 txid = ParseHashO(prevOut, "txid");
|
||||
|
||||
int nOut = find_value(prevOut, "vout").get_int();
|
||||
if (nOut < 0) {
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
|
||||
}
|
||||
|
||||
COutPoint out(txid, nOut);
|
||||
std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
|
||||
CScript scriptPubKey(pkData.begin(), pkData.end());
|
||||
|
||||
{
|
||||
auto coin = coins.find(out);
|
||||
if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
|
||||
std::string err("Previous output scriptPubKey mismatch:\n");
|
||||
err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
|
||||
ScriptToAsmStr(scriptPubKey);
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
|
||||
}
|
||||
Coin newcoin;
|
||||
newcoin.out.scriptPubKey = scriptPubKey;
|
||||
newcoin.out.nValue = 0;
|
||||
if (prevOut.exists("amount")) {
|
||||
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
|
||||
}
|
||||
newcoin.nHeight = 1;
|
||||
coins[out] = std::move(newcoin);
|
||||
}
|
||||
|
||||
// if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
|
||||
if (is_temp_keystore && scriptPubKey.IsPayToScriptHash()) {
|
||||
RPCTypeCheckObj(prevOut,
|
||||
{
|
||||
{"redeemScript", UniValueType(UniValue::VSTR)},
|
||||
});
|
||||
UniValue v = find_value(prevOut, "redeemScript");
|
||||
if (!v.isNull()) {
|
||||
std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
|
||||
CScript redeemScript(rsData.begin(), rsData.end());
|
||||
keystore->AddCScript(redeemScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nHashType = ParseSighashString(hashType);
|
||||
|
||||
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
|
||||
|
||||
// Script verification errors
|
||||
UniValue vErrors(UniValue::VARR);
|
||||
|
||||
// Use CTransaction for the constant parts of the
|
||||
// transaction to avoid rehashing.
|
||||
const CTransaction txConst(mtx);
|
||||
// Sign what we can:
|
||||
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
|
||||
CTxIn& txin = mtx.vin[i];
|
||||
auto coin = coins.find(txin.prevout);
|
||||
if (coin == coins.end() || coin->second.IsSpent()) {
|
||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
||||
continue;
|
||||
}
|
||||
const CScript& prevPubKey = coin->second.out.scriptPubKey;
|
||||
const CAmount& amount = coin->second.out.nValue;
|
||||
|
||||
SignatureData sigdata = DataFromTransaction(mtx, i, coin->second.out);
|
||||
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||
if (!fHashSingle || (i < mtx.vout.size())) {
|
||||
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
|
||||
}
|
||||
|
||||
UpdateInput(txin, sigdata);
|
||||
|
||||
ScriptError serror = SCRIPT_ERR_OK;
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
|
||||
if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
|
||||
// Unable to sign input and verification failed (possible attempt to partially sign).
|
||||
TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
|
||||
} else {
|
||||
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
|
||||
}
|
||||
}
|
||||
}
|
||||
bool fComplete = vErrors.empty();
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
|
||||
result.pushKV("complete", fComplete);
|
||||
if (!vErrors.empty()) {
|
||||
result.pushKV("errors", vErrors);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -2,12 +2,12 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_RPC_RAWTRANSACTION_H
|
||||
#define BITCOIN_RPC_RAWTRANSACTION_H
|
||||
#ifndef BITCOIN_RPC_RAWTRANSACTION_UTIL_H
|
||||
#define BITCOIN_RPC_RAWTRANSACTION_UTIL_H
|
||||
|
||||
class CBasicKeyStore;
|
||||
struct CMutableTransaction;
|
||||
class UniValue;
|
||||
struct CMutableTransaction;
|
||||
|
||||
namespace interfaces {
|
||||
class Chain;
|
||||
@ -19,4 +19,4 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
|
||||
/** Create a transaction from univalue parameters */
|
||||
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime);
|
||||
|
||||
#endif // BITCOIN_RPC_RAWTRANSACTION_H
|
||||
#endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
|
@ -54,150 +54,6 @@ void RPCServer::OnStopped(std::function<void ()> slot)
|
||||
g_rpcSignals.Stopped.connect(slot);
|
||||
}
|
||||
|
||||
void RPCTypeCheck(const UniValue& params,
|
||||
const std::list<UniValueType>& typesExpected,
|
||||
bool fAllowNull)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (const UniValueType& t : typesExpected) {
|
||||
if (params.size() <= i)
|
||||
break;
|
||||
|
||||
const UniValue& v = params[i];
|
||||
if (!(fAllowNull && v.isNull())) {
|
||||
RPCTypeCheckArgument(v, t);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
|
||||
{
|
||||
if (!typeExpected.typeAny && value.type() != typeExpected.type) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
|
||||
}
|
||||
}
|
||||
|
||||
void RPCTypeCheckObj(const UniValue& o,
|
||||
const std::map<std::string, UniValueType>& typesExpected,
|
||||
bool fAllowNull,
|
||||
bool fStrict)
|
||||
{
|
||||
for (const auto& t : typesExpected) {
|
||||
const UniValue& v = find_value(o, t.first);
|
||||
if (!fAllowNull && v.isNull())
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
|
||||
|
||||
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
|
||||
std::string err = strprintf("Expected type %s for %s, got %s",
|
||||
uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (fStrict)
|
||||
{
|
||||
for (const std::string& k : o.getKeys())
|
||||
{
|
||||
if (typesExpected.count(k) == 0)
|
||||
{
|
||||
std::string err = strprintf("Unexpected key %s", k);
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAmount AmountFromValue(const UniValue& value)
|
||||
{
|
||||
if (!value.isNum() && !value.isStr())
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
|
||||
CAmount amount;
|
||||
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
|
||||
if (!MoneyRange(amount))
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
|
||||
return amount;
|
||||
}
|
||||
|
||||
uint256 ParseHashV(const UniValue& v, std::string strName)
|
||||
{
|
||||
std::string strHex;
|
||||
if (v.isStr())
|
||||
strHex = v.get_str();
|
||||
if (!IsHex(strHex)) // Note: IsHex("") is false
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
|
||||
if (64 != strHex.length())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
|
||||
uint256 result;
|
||||
result.SetHex(strHex);
|
||||
return result;
|
||||
}
|
||||
uint256 ParseHashO(const UniValue& o, std::string strKey)
|
||||
{
|
||||
return ParseHashV(find_value(o, strKey), strKey);
|
||||
}
|
||||
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
|
||||
{
|
||||
std::string strHex;
|
||||
if (v.isStr())
|
||||
strHex = v.get_str();
|
||||
if (!IsHex(strHex))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
|
||||
return ParseHex(strHex);
|
||||
}
|
||||
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
|
||||
{
|
||||
return ParseHexV(find_value(o, strKey), strKey);
|
||||
}
|
||||
|
||||
int32_t ParseInt32V(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strNum = v.getValStr();
|
||||
int32_t num;
|
||||
if (!ParseInt32(strNum, &num))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a 32bit integer (not '"+strNum+"')");
|
||||
return num;
|
||||
}
|
||||
|
||||
int64_t ParseInt64V(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strNum = v.getValStr();
|
||||
int64_t num;
|
||||
if (!ParseInt64(strNum, &num))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a 64bit integer (not '"+strNum+"')");
|
||||
return num;
|
||||
}
|
||||
|
||||
double ParseDoubleV(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strNum = v.getValStr();
|
||||
double num;
|
||||
if (!ParseDouble(strNum, &num))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a be number (not '"+strNum+"')");
|
||||
return num;
|
||||
}
|
||||
|
||||
bool ParseBoolV(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strBool;
|
||||
if (v.isBool())
|
||||
return v.get_bool();
|
||||
else if (v.isNum())
|
||||
strBool = itostr(v.get_int());
|
||||
else if (v.isStr())
|
||||
strBool = v.get_str();
|
||||
|
||||
strBool = ToLower(strBool);
|
||||
|
||||
if (strBool == "true" || strBool == "yes" || strBool == "1") {
|
||||
return true;
|
||||
} else if (strBool == "false" || strBool == "no" || strBool == "0") {
|
||||
return false;
|
||||
}
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be true, false, yes, no, 1 or 0 (not '"+strBool+"')");
|
||||
}
|
||||
|
||||
std::string CRPCTable::help(const std::string& strCommand, const std::string& strSubCommand, const JSONRPCRequest& helpreq) const
|
||||
{
|
||||
std::string strRet;
|
||||
@ -662,18 +518,6 @@ std::vector<std::string> CRPCTable::listCommands() const
|
||||
return commandList;
|
||||
}
|
||||
|
||||
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
|
||||
{
|
||||
return "> dash-cli " + methodname + " " + args + "\n";
|
||||
}
|
||||
|
||||
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
|
||||
{
|
||||
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
|
||||
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;'"
|
||||
" http://127.0.0.1:" + strprintf("%d", gArgs.GetArg("-rpcport", BaseParams().RPCPort())) + "/\n";
|
||||
}
|
||||
|
||||
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
|
||||
{
|
||||
if (!timerInterface)
|
||||
|
@ -25,15 +25,6 @@ namespace RPCServer
|
||||
void OnStopped(std::function<void ()> slot);
|
||||
}
|
||||
|
||||
/** Wrapper for UniValue::VType, which includes typeAny:
|
||||
* Used to denote don't care type. */
|
||||
struct UniValueType {
|
||||
UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
|
||||
UniValueType() : typeAny(true) {}
|
||||
bool typeAny;
|
||||
UniValue::VType type;
|
||||
};
|
||||
|
||||
class JSONRPCRequest
|
||||
{
|
||||
public:
|
||||
@ -63,26 +54,6 @@ void SetRPCWarmupFinished();
|
||||
/* returns the current warmup state. */
|
||||
bool RPCIsInWarmup(std::string *outStatus);
|
||||
|
||||
/**
|
||||
* Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
|
||||
* the right number of arguments are passed, just that any passed are the correct type.
|
||||
*/
|
||||
void RPCTypeCheck(const UniValue& params,
|
||||
const std::list<UniValueType>& typesExpected, bool fAllowNull=false);
|
||||
|
||||
/**
|
||||
* Type-check one argument; throws JSONRPCError if wrong type given.
|
||||
*/
|
||||
void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected);
|
||||
|
||||
/*
|
||||
Check for expected keys/value types in an Object.
|
||||
*/
|
||||
void RPCTypeCheckObj(const UniValue& o,
|
||||
const std::map<std::string, UniValueType>& typesExpected,
|
||||
bool fAllowNull = false,
|
||||
bool fStrict = false);
|
||||
|
||||
/** Opaque base class for timers returned by NewTimerFunc.
|
||||
* This provides no methods at the moment, but makes sure that delete
|
||||
* cleans up the whole state.
|
||||
@ -204,24 +175,6 @@ bool IsDeprecatedRPCEnabled(const std::string& method);
|
||||
|
||||
extern CRPCTable tableRPC;
|
||||
|
||||
/**
|
||||
* Utilities: convert hex-encoded Values
|
||||
* (throws error if not hex).
|
||||
*/
|
||||
extern uint256 ParseHashV(const UniValue& v, std::string strName);
|
||||
extern uint256 ParseHashO(const UniValue& o, std::string strKey);
|
||||
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
|
||||
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
|
||||
|
||||
extern int32_t ParseInt32V(const UniValue& v, const std::string &strName);
|
||||
extern int64_t ParseInt64V(const UniValue& v, const std::string &strName);
|
||||
extern double ParseDoubleV(const UniValue& v, const std::string &strName);
|
||||
extern bool ParseBoolV(const UniValue& v, const std::string &strName);
|
||||
|
||||
extern CAmount AmountFromValue(const UniValue& value);
|
||||
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
|
||||
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
|
||||
|
||||
void StartRPC();
|
||||
void InterruptRPC();
|
||||
void StopRPC();
|
||||
|
158
src/rpc/util.cpp
158
src/rpc/util.cpp
@ -2,15 +2,173 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <chainparamsbase.h>
|
||||
#include <key_io.h>
|
||||
#include <keystore.h>
|
||||
#include <pubkey.h>
|
||||
#include <rpc/util.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
InitInterfaces* g_rpc_interfaces = nullptr;
|
||||
|
||||
void RPCTypeCheck(const UniValue& params,
|
||||
const std::list<UniValueType>& typesExpected,
|
||||
bool fAllowNull)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (const UniValueType& t : typesExpected) {
|
||||
if (params.size() <= i)
|
||||
break;
|
||||
|
||||
const UniValue& v = params[i];
|
||||
if (!(fAllowNull && v.isNull())) {
|
||||
RPCTypeCheckArgument(v, t);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
|
||||
{
|
||||
if (!typeExpected.typeAny && value.type() != typeExpected.type) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
|
||||
}
|
||||
}
|
||||
|
||||
void RPCTypeCheckObj(const UniValue& o,
|
||||
const std::map<std::string, UniValueType>& typesExpected,
|
||||
bool fAllowNull,
|
||||
bool fStrict)
|
||||
{
|
||||
for (const auto& t : typesExpected) {
|
||||
const UniValue& v = find_value(o, t.first);
|
||||
if (!fAllowNull && v.isNull())
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
|
||||
|
||||
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
|
||||
std::string err = strprintf("Expected type %s for %s, got %s",
|
||||
uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (fStrict)
|
||||
{
|
||||
for (const std::string& k : o.getKeys())
|
||||
{
|
||||
if (typesExpected.count(k) == 0)
|
||||
{
|
||||
std::string err = strprintf("Unexpected key %s", k);
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAmount AmountFromValue(const UniValue& value)
|
||||
{
|
||||
if (!value.isNum() && !value.isStr())
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
|
||||
CAmount amount;
|
||||
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
|
||||
if (!MoneyRange(amount))
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
|
||||
return amount;
|
||||
}
|
||||
|
||||
uint256 ParseHashV(const UniValue& v, std::string strName)
|
||||
{
|
||||
std::string strHex;
|
||||
if (v.isStr())
|
||||
strHex = v.get_str();
|
||||
if (!IsHex(strHex)) // Note: IsHex("") is false
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
|
||||
if (64 != strHex.length())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
|
||||
uint256 result;
|
||||
result.SetHex(strHex);
|
||||
return result;
|
||||
}
|
||||
uint256 ParseHashO(const UniValue& o, std::string strKey)
|
||||
{
|
||||
return ParseHashV(find_value(o, strKey), strKey);
|
||||
}
|
||||
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
|
||||
{
|
||||
std::string strHex;
|
||||
if (v.isStr())
|
||||
strHex = v.get_str();
|
||||
if (!IsHex(strHex))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
|
||||
return ParseHex(strHex);
|
||||
}
|
||||
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
|
||||
{
|
||||
return ParseHexV(find_value(o, strKey), strKey);
|
||||
}
|
||||
|
||||
int32_t ParseInt32V(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strNum = v.getValStr();
|
||||
int32_t num;
|
||||
if (!ParseInt32(strNum, &num))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a 32bit integer (not '"+strNum+"')");
|
||||
return num;
|
||||
}
|
||||
|
||||
int64_t ParseInt64V(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strNum = v.getValStr();
|
||||
int64_t num;
|
||||
if (!ParseInt64(strNum, &num))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a 64bit integer (not '"+strNum+"')");
|
||||
return num;
|
||||
}
|
||||
|
||||
double ParseDoubleV(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strNum = v.getValStr();
|
||||
double num;
|
||||
if (!ParseDouble(strNum, &num))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a be number (not '"+strNum+"')");
|
||||
return num;
|
||||
}
|
||||
|
||||
bool ParseBoolV(const UniValue& v, const std::string &strName)
|
||||
{
|
||||
std::string strBool;
|
||||
if (v.isBool())
|
||||
return v.get_bool();
|
||||
else if (v.isNum())
|
||||
strBool = itostr(v.get_int());
|
||||
else if (v.isStr())
|
||||
strBool = v.get_str();
|
||||
|
||||
strBool = ToLower(strBool);
|
||||
|
||||
if (strBool == "true" || strBool == "yes" || strBool == "1") {
|
||||
return true;
|
||||
} else if (strBool == "false" || strBool == "no" || strBool == "0") {
|
||||
return false;
|
||||
}
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be true, false, yes, no, 1 or 0 (not '"+strBool+"')");
|
||||
}
|
||||
|
||||
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
|
||||
{
|
||||
return "> dash-cli " + methodname + " " + args + "\n";
|
||||
}
|
||||
|
||||
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
|
||||
{
|
||||
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
|
||||
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;'"
|
||||
" http://127.0.0.1:" + strprintf("%d", gArgs.GetArg("-rpcport", BaseParams().RPCPort())) + "/\n";
|
||||
}
|
||||
|
||||
// Converts a hex string to a public key if possible
|
||||
CPubKey HexToPubKey(const std::string& hex_in)
|
||||
{
|
||||
|
@ -28,6 +28,53 @@ struct InitInterfaces;
|
||||
//! state to RPC method implementations.
|
||||
extern InitInterfaces* g_rpc_interfaces;
|
||||
|
||||
/** Wrapper for UniValue::VType, which includes typeAny:
|
||||
* Used to denote don't care type. */
|
||||
struct UniValueType {
|
||||
UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
|
||||
UniValueType() : typeAny(true) {}
|
||||
bool typeAny;
|
||||
UniValue::VType type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
|
||||
* the right number of arguments are passed, just that any passed are the correct type.
|
||||
*/
|
||||
void RPCTypeCheck(const UniValue& params,
|
||||
const std::list<UniValueType>& typesExpected, bool fAllowNull=false);
|
||||
|
||||
/**
|
||||
* Type-check one argument; throws JSONRPCError if wrong type given.
|
||||
*/
|
||||
void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected);
|
||||
|
||||
/*
|
||||
Check for expected keys/value types in an Object.
|
||||
*/
|
||||
void RPCTypeCheckObj(const UniValue& o,
|
||||
const std::map<std::string, UniValueType>& typesExpected,
|
||||
bool fAllowNull = false,
|
||||
bool fStrict = false);
|
||||
|
||||
/**
|
||||
* Utilities: convert hex-encoded Values
|
||||
* (throws error if not hex).
|
||||
*/
|
||||
extern uint256 ParseHashV(const UniValue& v, std::string strName);
|
||||
extern uint256 ParseHashO(const UniValue& o, std::string strKey);
|
||||
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
|
||||
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
|
||||
|
||||
extern int32_t ParseInt32V(const UniValue& v, const std::string &strName);
|
||||
extern int64_t ParseInt64V(const UniValue& v, const std::string &strName);
|
||||
extern double ParseDoubleV(const UniValue& v, const std::string &strName);
|
||||
extern bool ParseBoolV(const UniValue& v, const std::string &strName);
|
||||
|
||||
extern CAmount AmountFromValue(const UniValue& value);
|
||||
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
|
||||
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
|
||||
|
||||
CPubKey HexToPubKey(const std::string& hex_in);
|
||||
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in);
|
||||
CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys);
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <protocol.h>
|
||||
#include <script/standard.h>
|
||||
#include <timedata.h>
|
||||
#include <validation.h>
|
||||
#include <util/validation.h> // for strMessageMagic
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <policy/policy.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <policy/settings.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/ismine.h>
|
||||
#include <test/setup_common.h>
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <script/sign.h>
|
||||
#include <util/system.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <rpc/util.h>
|
||||
#include <test/setup_common.h>
|
||||
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <test/data/sighash.json.h>
|
||||
#include <hash.h>
|
||||
|
@ -8,13 +8,14 @@
|
||||
|
||||
#include <clientversion.h>
|
||||
#include <checkqueue.h>
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <core_io.h>
|
||||
#include <key.h>
|
||||
#include <keystore.h>
|
||||
#include <validation.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <util/strencodings.h>
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <validation.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/settings.h>
|
||||
#include <reverse_iterator.h>
|
||||
#include <streams.h>
|
||||
#include <timedata.h>
|
||||
|
@ -6,6 +6,32 @@
|
||||
|
||||
#include <util/system.h>
|
||||
|
||||
std::string TransactionErrorString(const TransactionError err)
|
||||
{
|
||||
switch (err) {
|
||||
case TransactionError::OK:
|
||||
return "No error";
|
||||
case TransactionError::MISSING_INPUTS:
|
||||
return "Missing inputs";
|
||||
case TransactionError::ALREADY_IN_CHAIN:
|
||||
return "Transaction already in block chain";
|
||||
case TransactionError::P2P_DISABLED:
|
||||
return "Peer-to-peer functionality missing or disabled";
|
||||
case TransactionError::MEMPOOL_REJECTED:
|
||||
return "Transaction rejected by AcceptToMemoryPool";
|
||||
case TransactionError::MEMPOOL_ERROR:
|
||||
return "AcceptToMemoryPool failed";
|
||||
case TransactionError::INVALID_PSBT:
|
||||
return "PSBT is not sane";
|
||||
case TransactionError::PSBT_MISMATCH:
|
||||
return "PSBTs not compatible (different transactions)";
|
||||
case TransactionError::SIGHASH_MISMATCH:
|
||||
return "Specified sighash value does not match existing value";
|
||||
// no default case, so the compiler can warn about missing cases
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
std::string AmountHighWarn(const std::string& optname)
|
||||
{
|
||||
return strprintf(_("%s is set very high!"), optname);
|
||||
|
@ -17,6 +17,20 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class TransactionError {
|
||||
OK, //!< No error
|
||||
MISSING_INPUTS,
|
||||
ALREADY_IN_CHAIN,
|
||||
P2P_DISABLED,
|
||||
MEMPOOL_REJECTED,
|
||||
MEMPOOL_ERROR,
|
||||
INVALID_PSBT,
|
||||
PSBT_MISMATCH,
|
||||
SIGHASH_MISMATCH,
|
||||
};
|
||||
|
||||
std::string TransactionErrorString(const TransactionError error);
|
||||
|
||||
std::string AmountHighWarn(const std::string& optname);
|
||||
std::string AmountErrMsg(const char* const optname, const std::string& strValue);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <checkqueue.h>
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/merkle.h>
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <cuckoocache.h>
|
||||
@ -22,6 +23,7 @@
|
||||
#include <logging/timer.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <pow.h>
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
@ -141,7 +143,6 @@ bool fTimestampIndex = false;
|
||||
bool fSpentIndex = false;
|
||||
bool fHavePruned = false;
|
||||
bool fPruneMode = false;
|
||||
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
|
||||
bool fRequireStandard = true;
|
||||
bool fCheckBlockIndex = false;
|
||||
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
|
||||
|
@ -83,8 +83,6 @@ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
|
||||
|
||||
static const int64_t DEFAULT_MAX_TIP_AGE = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin
|
||||
|
||||
/** Default for -permitbaremultisig */
|
||||
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
|
||||
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
|
||||
static const bool DEFAULT_TXINDEX = true;
|
||||
static const bool DEFAULT_ADDRESSINDEX = false;
|
||||
@ -130,7 +128,6 @@ typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
|
||||
typedef std::unordered_multimap<uint256, CBlockIndex*, BlockHasher> PrevBlockMap;
|
||||
extern uint64_t nLastBlockTx;
|
||||
extern uint64_t nLastBlockSize;
|
||||
extern const std::string strMessageMagic;
|
||||
extern Mutex g_best_block_mutex;
|
||||
extern std::condition_variable g_best_block_cv;
|
||||
extern uint256 g_best_block;
|
||||
@ -139,7 +136,6 @@ extern std::atomic_bool fReindex;
|
||||
extern bool fAddressIndex;
|
||||
extern bool fTimestampIndex;
|
||||
extern bool fSpentIndex;
|
||||
extern bool fIsBareMultisigStd;
|
||||
/** Whether there are dedicated script-checking threads running.
|
||||
* False indicates all script checking is done on the main threadMessageHandler thread.
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <wallet/fees.h>
|
||||
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <util/system.h>
|
||||
#include <validation.h>
|
||||
#include <wallet/coincontrol.h>
|
||||
|
@ -256,58 +256,6 @@ bool WalletInit::ParameterInteraction() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
|
||||
{
|
||||
if (gArgs.IsArgSet("-walletdir")) {
|
||||
fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
|
||||
boost::system::error_code error;
|
||||
// The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
|
||||
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
|
||||
if (error || !fs::exists(wallet_dir)) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
|
||||
return false;
|
||||
} else if (!fs::is_directory(wallet_dir)) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
|
||||
return false;
|
||||
// The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
|
||||
} else if (!wallet_dir.is_absolute()) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
|
||||
return false;
|
||||
}
|
||||
gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
|
||||
}
|
||||
|
||||
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
|
||||
|
||||
chain.initMessage(_("Verifying wallet(s)..."));
|
||||
|
||||
// Parameter interaction code should have thrown an error if -salvagewallet
|
||||
// was enabled with more than wallet file, so the wallet_files size check
|
||||
// here should have no effect.
|
||||
bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;
|
||||
|
||||
// Keep track of each wallet absolute path to detect duplicates.
|
||||
std::set<fs::path> wallet_paths;
|
||||
|
||||
for (const auto& wallet_file : wallet_files) {
|
||||
WalletLocation location(wallet_file);
|
||||
|
||||
if (!wallet_paths.insert(location.GetPath()).second) {
|
||||
chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string error_string;
|
||||
std::string warning_string;
|
||||
bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warning_string);
|
||||
if (!error_string.empty()) chain.initError(error_string);
|
||||
if (!warning_string.empty()) chain.initWarning(warning_string);
|
||||
if (!verify_success) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WalletInit::Construct(InitInterfaces& interfaces) const
|
||||
{
|
||||
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
|
||||
@ -318,62 +266,6 @@ void WalletInit::Construct(InitInterfaces& interfaces) const
|
||||
interfaces.chain_clients.emplace_back(interfaces::MakeWalletClient(*interfaces.chain, gArgs.GetArgs("-wallet")));
|
||||
}
|
||||
|
||||
bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
|
||||
{
|
||||
for (const std::string& walletFile : wallet_files) {
|
||||
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile));
|
||||
if (!pwallet) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StartWallets(CScheduler& scheduler)
|
||||
{
|
||||
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
|
||||
pwallet->postInitProcess();
|
||||
}
|
||||
|
||||
// Run a thread to flush wallet periodically
|
||||
scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
|
||||
|
||||
if (!fMasternodeMode && CCoinJoinClientOptions::IsEnabled()) {
|
||||
scheduler.scheduleEvery(std::bind(&DoCoinJoinMaintenance, std::ref(*g_connman)), 1 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void FlushWallets()
|
||||
{
|
||||
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
|
||||
if (CCoinJoinClientOptions::IsEnabled()) {
|
||||
// Stop CoinJoin, release keys
|
||||
auto it = coinJoinClientManagers.find(pwallet->GetName());
|
||||
it->second->ResetPool();
|
||||
it->second->StopMixing();
|
||||
}
|
||||
pwallet->Flush(false);
|
||||
}
|
||||
}
|
||||
|
||||
void StopWallets()
|
||||
{
|
||||
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
|
||||
pwallet->Flush(true);
|
||||
}
|
||||
}
|
||||
|
||||
void UnloadWallets()
|
||||
{
|
||||
auto wallets = GetWallets();
|
||||
while (!wallets.empty()) {
|
||||
auto wallet = wallets.back();
|
||||
wallets.pop_back();
|
||||
RemoveWallet(wallet);
|
||||
UnloadWallet(std::move(wallet));
|
||||
}
|
||||
}
|
||||
|
||||
void WalletInit::AutoLockMasternodeCollaterals() const
|
||||
{
|
||||
|
123
src/wallet/load.cpp
Normal file
123
src/wallet/load.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <wallet/load.h>
|
||||
|
||||
#include <net.h>
|
||||
#include <coinjoin/client.h>
|
||||
#include <coinjoin/options.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <scheduler.h>
|
||||
#include <util/system.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
|
||||
{
|
||||
if (gArgs.IsArgSet("-walletdir")) {
|
||||
fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
|
||||
boost::system::error_code error;
|
||||
// The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
|
||||
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
|
||||
if (error || !fs::exists(wallet_dir)) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
|
||||
return false;
|
||||
} else if (!fs::is_directory(wallet_dir)) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
|
||||
return false;
|
||||
// The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
|
||||
} else if (!wallet_dir.is_absolute()) {
|
||||
chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
|
||||
return false;
|
||||
}
|
||||
gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
|
||||
}
|
||||
|
||||
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
|
||||
|
||||
chain.initMessage(_("Verifying wallet(s)..."));
|
||||
|
||||
// Parameter interaction code should have thrown an error if -salvagewallet
|
||||
// was enabled with more than wallet file, so the wallet_files size check
|
||||
// here should have no effect.
|
||||
bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;
|
||||
|
||||
// Keep track of each wallet absolute path to detect duplicates.
|
||||
std::set<fs::path> wallet_paths;
|
||||
|
||||
for (const auto& wallet_file : wallet_files) {
|
||||
WalletLocation location(wallet_file);
|
||||
|
||||
if (!wallet_paths.insert(location.GetPath()).second) {
|
||||
chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string error_string;
|
||||
std::string warning_string;
|
||||
bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warning_string);
|
||||
if (!error_string.empty()) chain.initError(error_string);
|
||||
if (!warning_string.empty()) chain.initWarning(warning_string);
|
||||
if (!verify_success) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
|
||||
{
|
||||
for (const std::string& walletFile : wallet_files) {
|
||||
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile));
|
||||
if (!pwallet) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StartWallets(CScheduler& scheduler)
|
||||
{
|
||||
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
|
||||
pwallet->postInitProcess();
|
||||
}
|
||||
|
||||
// Run a thread to flush wallet periodically
|
||||
scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
|
||||
|
||||
if (!fMasternodeMode && CCoinJoinClientOptions::IsEnabled()) {
|
||||
scheduler.scheduleEvery(std::bind(&DoCoinJoinMaintenance, std::ref(*g_connman)), 1 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void FlushWallets()
|
||||
{
|
||||
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
|
||||
if (CCoinJoinClientOptions::IsEnabled()) {
|
||||
// Stop CoinJoin, release keys
|
||||
auto it = coinJoinClientManagers.find(pwallet->GetName());
|
||||
it->second->ResetPool();
|
||||
it->second->StopMixing();
|
||||
}
|
||||
pwallet->Flush(false);
|
||||
}
|
||||
}
|
||||
|
||||
void StopWallets()
|
||||
{
|
||||
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
|
||||
pwallet->Flush(true);
|
||||
}
|
||||
}
|
||||
|
||||
void UnloadWallets()
|
||||
{
|
||||
auto wallets = GetWallets();
|
||||
while (!wallets.empty()) {
|
||||
auto wallet = wallets.back();
|
||||
wallets.pop_back();
|
||||
RemoveWallet(wallet);
|
||||
UnloadWallet(std::move(wallet));
|
||||
}
|
||||
}
|
38
src/wallet/load.h
Normal file
38
src/wallet/load.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_WALLET_LOAD_H
|
||||
#define BITCOIN_WALLET_LOAD_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CScheduler;
|
||||
|
||||
namespace interfaces {
|
||||
class Chain;
|
||||
} // namespace interfaces
|
||||
|
||||
//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
|
||||
//! This function will perform salvage on the wallet if requested, as long as only one wallet is
|
||||
//! being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
|
||||
bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
|
||||
|
||||
//! Load wallet databases.
|
||||
bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
|
||||
|
||||
//! Complete startup of wallets.
|
||||
void StartWallets(CScheduler& scheduler);
|
||||
|
||||
//! Flush all wallets in preparation for shutdown.
|
||||
void FlushWallets();
|
||||
|
||||
//! Stop all wallets. Wallets will be flushed first.
|
||||
void StopWallets();
|
||||
|
||||
//! Close all wallets.
|
||||
void UnloadWallets();
|
||||
|
||||
#endif // BITCOIN_WALLET_LOAD_H
|
@ -18,7 +18,7 @@
|
||||
#include <policy/feerate.h>
|
||||
#include <policy/fees.h>
|
||||
#include <rpc/mining.h>
|
||||
#include <rpc/rawtransaction.h>
|
||||
#include <rpc/rawtransaction_util.h>
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/descriptor.h>
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <net.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script.h>
|
||||
|
@ -39,26 +39,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
|
||||
// This function will perform salvage on the wallet if requested, as long as only one wallet is
|
||||
// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
|
||||
bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
|
||||
|
||||
//! Load wallet databases.
|
||||
bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
|
||||
|
||||
//! Complete startup of wallets.
|
||||
void StartWallets(CScheduler& scheduler);
|
||||
|
||||
//! Flush all wallets in preparation for shutdown.
|
||||
void FlushWallets();
|
||||
|
||||
//! Stop all wallets. Wallets will be flushed first.
|
||||
void StopWallets();
|
||||
|
||||
//! Close all wallets.
|
||||
void UnloadWallets();
|
||||
|
||||
//! Explicitly unload and delete the wallet.
|
||||
// Blocks the current thread after signaling the unload intent so that all
|
||||
// wallet clients release the wallet.
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <wallet/walletdb.h>
|
||||
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <key_io.h>
|
||||
#include <fs.h>
|
||||
|
@ -12,7 +12,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
|
||||
"chainparamsbase -> util/system -> chainparamsbase"
|
||||
"index/txindex -> validation -> index/txindex"
|
||||
"policy/fees -> txmempool -> policy/fees"
|
||||
"policy/policy -> validation -> policy/policy"
|
||||
"policy/policy -> policy/settings -> policy/policy"
|
||||
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel"
|
||||
"qt/bantablemodel -> qt/clientmodel -> qt/bantablemodel"
|
||||
"qt/bitcoingui -> qt/utilitydialog -> qt/bitcoingui"
|
||||
@ -29,6 +29,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
|
||||
"wallet/wallet -> wallet/walletdb -> wallet/wallet"
|
||||
"wallet/coincontrol -> wallet/wallet -> wallet/coincontrol"
|
||||
"policy/fees -> policy/policy -> validation -> policy/fees"
|
||||
"policy/policy -> validation -> policy/policy"
|
||||
"qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/addressbookpage"
|
||||
"txmempool -> validation -> validationinterface -> txmempool"
|
||||
"qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/receivecoinsdialog -> qt/addressbookpage"
|
||||
|
Loading…
Reference in New Issue
Block a user