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:
Kittywhiskers Van Gogh 2021-11-16 20:49:47 +05:30 committed by GitHub
parent a3a8bfee08
commit d978259654
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 841 additions and 734 deletions

View File

@ -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 \

View 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
View 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

View File

@ -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?

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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
View 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.

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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);

View File

@ -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
View 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
View 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

View File

@ -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>

View File

@ -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)

View 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;
}

View File

@ -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

View File

@ -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)

View File

@ -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();

View File

@ -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)
{

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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.
*/

View File

@ -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>

View File

@ -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
View 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
View 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

View File

@ -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>

View File

@ -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>

View File

@ -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.

View File

@ -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>

View File

@ -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"