Merge pull request #4575 from Munkybooty/backports-0.19-pr7

Backports 0.19 pr7
This commit is contained in:
PastaPastaPasta 2022-02-15 23:31:21 +07:00 committed by GitHub
commit 9789a42088
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 463 additions and 276 deletions

View File

@ -61,21 +61,15 @@ The title of the pull request should be prefixed by the component or area that
the pull request affects. Valid areas as:
- *Consensus* for changes to consensus critical code
- *Docs* for changes to the documentation
- *Doc* for changes to the documentation
- *Qt* for changes to dash-qt
- *Log* Changes to log messages
- *Mining* for changes to the mining code
- *Net* or *P2P* for changes to the peer-to-peer network code
- *Refactor* for structural changes that do not change behavior
- *RPC/REST/ZMQ* for changes to the RPC, REST or ZMQ APIs
- *Scripts and tools* for changes to the scripts and tools
- *Tests* for changes to the unit tests or QA tests
- *Trivial* should **only** be used for PRs that do not change generated
executable code. Notably, refactors (change of function arguments and code
reorganization) and changes in behavior should **not** be marked as trivial.
Examples of trivial PRs are changes to:
- comments
- whitespace
- variable names
- logging and messages
- *Test* for changes to the unit tests or QA tests
- *Utils and libraries* for changes to the utils and libraries
- *Wallet* for changes to the wallet code
@ -84,10 +78,10 @@ Examples:
Consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG
Net: Automatically create hidden service, listen on Tor
Qt: Add feed bump button
Trivial: Fix typo in init.cpp
Log: Fix typo in log message
Note that translations should not be submitted as pull requests, please see
[Translation Process](https://github.com/dashpay/dash/blob/master/doc/translation_process.md)
[Translation Process](https://github.com/dashpay/dash/blob/master/doc/translation_process.md)
for more information on helping with translations.
If a pull request is not to be considered for merging (yet), please
@ -424,7 +418,7 @@ The project leader is the release manager for each Dash Core release.
Copyright
---------
By contributing to this repository, you agree to license your work under the
MIT license unless specified otherwise in `contrib/debian/copyright` or at
the top of the file itself. Any work contributed where you are not the original
By contributing to this repository, you agree to license your work under the
MIT license unless specified otherwise in `contrib/debian/copyright` or at
the top of the file itself. Any work contributed where you are not the original
author must contain its license header with the original author(s) and source.

View File

@ -43,6 +43,7 @@ $(package)_config_opts += -no-freetype
$(package)_config_opts += -no-gif
$(package)_config_opts += -no-glib
$(package)_config_opts += -no-icu
$(package)_config_opts += -no-ico
$(package)_config_opts += -no-iconv
$(package)_config_opts += -no-kms
$(package)_config_opts += -no-linuxfb
@ -79,19 +80,35 @@ $(package)_config_opts += -qt-harfbuzz
$(package)_config_opts += -system-zlib
$(package)_config_opts += -static
$(package)_config_opts += -v
$(package)_config_opts += -no-feature-bearermanagement
$(package)_config_opts += -no-feature-colordialog
$(package)_config_opts += -no-feature-commandlineparser
$(package)_config_opts += -no-feature-concurrent
$(package)_config_opts += -no-feature-dial
$(package)_config_opts += -no-feature-filesystemwatcher
$(package)_config_opts += -no-feature-fontcombobox
$(package)_config_opts += -no-feature-ftp
$(package)_config_opts += -no-feature-image_heuristic_mask
$(package)_config_opts += -no-feature-keysequenceedit
$(package)_config_opts += -no-feature-lcdnumber
$(package)_config_opts += -no-feature-pdf
$(package)_config_opts += -no-feature-printer
$(package)_config_opts += -no-feature-printdialog
$(package)_config_opts += -no-feature-concurrent
$(package)_config_opts += -no-feature-printer
$(package)_config_opts += -no-feature-printpreviewdialog
$(package)_config_opts += -no-feature-printpreviewwidget
$(package)_config_opts += -no-feature-sessionmanager
$(package)_config_opts += -no-feature-sql
$(package)_config_opts += -no-feature-statemachine
$(package)_config_opts += -no-feature-syntaxhighlighter
$(package)_config_opts += -no-feature-textbrowser
$(package)_config_opts += -no-feature-textodfwriter
$(package)_config_opts += -no-feature-topleveldomain
$(package)_config_opts += -no-feature-udpsocket
$(package)_config_opts += -no-feature-undocommand
$(package)_config_opts += -no-feature-undogroup
$(package)_config_opts += -no-feature-undostack
$(package)_config_opts += -no-feature-undoview
$(package)_config_opts += -no-feature-vnc
$(package)_config_opts += -no-feature-wizard
$(package)_config_opts += -no-feature-xml
@ -116,7 +133,6 @@ $(package)_config_opts_linux += -qt-xcb
$(package)_config_opts_linux += -no-xcb-xlib
$(package)_config_opts_linux += -no-feature-xlib
$(package)_config_opts_linux += -system-freetype
$(package)_config_opts_linux += -no-feature-sessionmanager
$(package)_config_opts_linux += -fontconfig
$(package)_config_opts_linux += -no-opengl
$(package)_config_opts_linux += -dbus-runtime

View File

@ -12,7 +12,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.18.0**):
* [`BIP 31`](https://github.com/bitcoin/bips/blob/master/bip-0031.mediawiki): The 'pong' protocol message (and the protocol version bump to 60001) has been implemented since **v0.6.1** ([PR #1081](https://github.com/bitcoin/bitcoin/pull/1081)).
* [`BIP 32`](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki): Hierarchical Deterministic Wallets has been implemented since **v0.13.0** ([PR #8035](https://github.com/bitcoin/bitcoin/pull/8035)).
* [`BIP 34`](https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki): The rule that requires blocks to contain their height (number) in the coinbase input, and the introduction of version 2 blocks has been implemented since **v0.7.0**. The rule took effect for version 2 blocks as of *block 224413* (March 5th 2013), and version 1 blocks are no longer allowed since *block 227931* (March 25th 2013) ([PR #1526](https://github.com/bitcoin/bitcoin/pull/1526)).
* [`BIP 35`](https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki): The 'mempool' protocol message (and the protocol version bump to 60002) has been implemented since **v0.7.0** ([PR #1641](https://github.com/bitcoin/bitcoin/pull/1641)).
* [`BIP 35`](https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki): The 'mempool' protocol message (and the protocol version bump to 60002) has been implemented since **v0.7.0** ([PR #1641](https://github.com/bitcoin/bitcoin/pull/1641)). As of **v0.13.0**, this is only available for `NODE_BLOOM` (BIP 111) peers.
* [`BIP 37`](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki): The bloom filtering for transaction relaying, partial Merkle trees for blocks, and the protocol version bump to 70001 (enabling low-bandwidth SPV clients) has been implemented since **v0.8.0** ([PR #1795](https://github.com/bitcoin/bitcoin/pull/1795)).
* [`BIP 42`](https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki): The bug that would have caused the subsidy schedule to resume after block 13440000 was fixed in **v0.9.2** ([PR #3842](https://github.com/bitcoin/bitcoin/pull/3842)).
* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)). Starting *v0.16.0*, whether to send reject messages can be configured with the `-enablebip61` option.

View File

@ -444,7 +444,7 @@ libdash_server_a_SOURCES += dummywallet.cpp
endif
if ENABLE_ZMQ
libdash_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
libdash_zmq_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
libdash_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libdash_zmq_a_SOURCES = \
zmq/zmqabstractnotifier.cpp \

View File

@ -309,7 +309,7 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fRequireRoutableExternalIP = true;
fMineBlocksOnDemand = false;
m_is_test_chain = false;
fAllowMultipleAddressesFromGroup = false;
fAllowMultiplePorts = false;
nLLMQConnectionRetryTimeout = 60;
@ -522,7 +522,7 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fRequireRoutableExternalIP = true;
fMineBlocksOnDemand = false;
m_is_test_chain = true;
fAllowMultipleAddressesFromGroup = false;
fAllowMultiplePorts = true;
nLLMQConnectionRetryTimeout = 60;
@ -553,7 +553,6 @@ public:
// (the tx=... number in the ChainStateFlushed debug.log lines)
0.01 // * estimated number of transactions per second after that timestamp
};
}
};
@ -722,7 +721,7 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fRequireRoutableExternalIP = true;
fMineBlocksOnDemand = false;
m_is_test_chain = true;
fAllowMultipleAddressesFromGroup = true;
fAllowMultiplePorts = true;
nLLMQConnectionRetryTimeout = 60;
@ -904,9 +903,9 @@ public:
vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fRequireStandard = true;
fRequireRoutableExternalIP = false;
fMineBlocksOnDemand = true;
m_is_test_chain = true;
fAllowMultipleAddressesFromGroup = true;
fAllowMultiplePorts = true;
nLLMQConnectionRetryTimeout = 1; // must be lower then the LLMQ signing session timeout so that tests have control over failing behavior

View File

@ -71,13 +71,15 @@ public:
bool RequireStandard() const { return fRequireStandard; }
/** Require addresses specified with "-externalip" parameter to be routable */
bool RequireRoutableExternalIP() const { return fRequireRoutableExternalIP; }
/** If this chain is exclusively used for testing */
bool IsTestChain() const { return m_is_test_chain; }
uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
/** Minimum free space (in GB) needed for data directory */
uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
/** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
/** Whether it is possible to mine blocks on demand (no retargeting) */
bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
/** Allow multiple addresses to be selected from the same network group (e.g. 192.168.x.x) */
bool AllowMultipleAddressesFromGroup() const { return fAllowMultipleAddressesFromGroup; }
/** Allow nodes with the same address and multiple ports */
@ -130,7 +132,7 @@ protected:
bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fRequireRoutableExternalIP;
bool fMineBlocksOnDemand;
bool m_is_test_chain;
bool fAllowMultipleAddressesFromGroup;
bool fAllowMultiplePorts;
int nLLMQConnectionRetryTimeout;

View File

@ -7,7 +7,6 @@
#include <memory>
#include <string>
#include <vector>
/**
* CBaseChainParams defines the base parameters (shared between dash-cli and dashd)

View File

@ -1494,8 +1494,9 @@ bool AppInitParameterInteraction()
}
fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (chainparams.RequireStandard() && !fRequireStandard)
if (!chainparams.IsTestChain() && !fRequireStandard) {
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
}
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
if (!g_wallet_init_interface.ParameterInteraction()) return false;
@ -2130,7 +2131,9 @@ bool AppInitMain(InitInterfaces& interfaces)
break;
}
ResetBlockFailureFlags(nullptr);
if (gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL) >= 3) {
ResetBlockFailureFlags(nullptr);
}
}
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());

View File

@ -26,7 +26,8 @@
#ifdef ENABLE_WALLET
#include <qt/paymentserver.h>
#include <qt/walletcontroller.h>
#endif
#include <qt/walletmodel.h>
#endif // ENABLE_WALLET
#include <interfaces/handler.h>
#include <interfaces/node.h>
@ -219,12 +220,6 @@ BitcoinApplication::~BitcoinApplication()
delete window;
window = nullptr;
#ifdef ENABLE_WALLET
delete paymentServer;
paymentServer = nullptr;
delete m_wallet_controller;
m_wallet_controller = nullptr;
#endif
// Delete Qt-settings if user clicked on "Reset Options"
QSettings settings;
if(optionsModel && optionsModel->resetSettingsOnShutdown){
@ -344,24 +339,21 @@ void BitcoinApplication::initializeResult(bool success)
{
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
qInfo() << "Platform customization:" << gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM).c_str();
#ifdef ENABLE_WALLET
m_wallet_controller = new WalletController(m_node, optionsModel, this);
#ifdef ENABLE_BIP70
PaymentServer::LoadRootCAs();
#endif
if (paymentServer) {
paymentServer->setOptionsModel(optionsModel);
#ifdef ENABLE_BIP70
connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK);
#endif
}
#endif
clientModel = new ClientModel(m_node, optionsModel);
window->setClientModel(clientModel);
#ifdef ENABLE_WALLET
window->setWalletController(m_wallet_controller);
if (WalletModel::isWalletEnabled()) {
m_wallet_controller = new WalletController(m_node, optionsModel, this);
window->setWalletController(m_wallet_controller);
if (paymentServer) {
paymentServer->setOptionsModel(optionsModel);
#ifdef ENABLE_BIP70
PaymentServer::LoadRootCAs();
connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK);
#endif
}
}
#endif // ENABLE_WALLET
// If -min option passed, start window minimized (iconified) or minimized to tray
if (!gArgs.GetBoolArg("-min", false)) {
@ -579,8 +571,10 @@ int GuiMain(int argc, char* argv[])
// Start up the payment server early, too, so impatient users that click on
// dash: links repeatedly have their payment requests routed to this process:
app.createPaymentServer();
#endif
if (WalletModel::isWalletEnabled()) {
app.createPaymentServer();
}
#endif // ENABLE_WALLET
/// 9. Main GUI initialization
// Install global event filter that makes sure that out-of-focus labels do not contain text cursor.

View File

@ -269,9 +269,12 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed;
}
// Reject absurdly high fee
if (nFeeRequired > m_wallet->getDefaultMaxTxFee())
// Reject absurdly high fee. (This can never happen because the
// wallet never creates transactions with fee greater than
// m_default_max_tx_fee. This merely a belt-and-suspenders check).
if (nFeeRequired > m_wallet->getDefaultMaxTxFee()) {
return AbsurdFee;
}
return SendCoinsReturn(OK);
}

View File

@ -771,7 +771,10 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
UniValue sendrawtransaction(const JSONRPCRequest& request)
{
const RPCHelpMan help{"sendrawtransaction", "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
const RPCHelpMan help{"sendrawtransaction", "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nNote that the transaction will be sent unconditionally to all peers, so using this\n"
"for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
"nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n"
"\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},

View File

@ -58,6 +58,9 @@ CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_contr
// if we don't have enough data for estimateSmartFee, then use fallback fee
feerate_needed = wallet.m_fallback_fee;
if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
// directly return if fallback fee is disabled (feerate 0 == disabled)
if (wallet.m_fallback_fee.GetFee(1000) == 0) return feerate_needed;
}
// Obey mempool min fee when using smart fee estimation
CFeeRate min_mempool_feerate = wallet.chain().mempoolMinFee();

View File

@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
#include <init.h>
#include <interfaces/chain.h>
#include <net.h>

View File

@ -478,9 +478,9 @@ public:
const std::string strUnableToLocateCoinJoin1 = "Unable to locate enough non-denominated funds for this transaction.";
const std::string strUnableToLocateCoinJoin2 = "Unable to locate enough mixed funds for this transaction. CoinJoin uses exact denominated amounts to send funds, you might simply need to mix some more coins.";
const std::string strTransactionTooLarge = "Transaction too large";
const std::string strTransactionTooLargeForFeePolicy = "Transaction too large for fee policy";
const std::string strChangeIndexOutOfRange = "Change index out of range";
const std::string strExceededMaxTries = "Exceeded max tries.";
const std::string strMaxFeeExceeded = "Fee exceeds maximum configured by -maxtxfee";
CreateTransactionTestSetup()
{
@ -886,13 +886,9 @@ BOOST_FIXTURE_TEST_CASE(CreateTransactionTest, CreateTransactionTestSetup)
createOutputEntries(2935);
BOOST_CHECK(CreateTransaction(vecOutputEntries, strTransactionTooLarge, false));
auto prevRate = minRelayTxFee;
coinControl.m_feerate = prevRate;
coinControl.fOverrideFeeRate = true;
minRelayTxFee = CFeeRate(prevRate.GetFeePerK() * 10);
BOOST_CHECK(CreateTransaction({{5000, false}}, strTransactionTooLargeForFeePolicy, false));
coinControl.m_feerate.reset();
minRelayTxFee = prevRate;
wallet->m_default_max_tx_fee = 0;
BOOST_CHECK(CreateTransaction({{5000, false}}, strMaxFeeExceeded, false));
wallet->m_default_max_tx_fee = DEFAULT_TRANSACTION_MAXFEE;
BOOST_CHECK(CreateTransaction({{5000, false}, {5000, false}, {5000, false}}, strChangeIndexOutOfRange, 4, false));
}

View File

@ -169,7 +169,7 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string&
return LoadWallet(chain, WalletLocation(name), error, warning);
}
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
const uint256 CWalletTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
/** @defgroup mapWallet
*
@ -3236,11 +3236,6 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
}
if (nFeeRet > m_default_max_tx_fee) {
strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
return false;
}
return true;
}
@ -3722,13 +3717,6 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
nFee = GetMinimumFee(*this, nBytes, coin_control, &feeCalc);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
if (nFee < ::minRelayTxFee.GetFee(nBytes)) {
strFailReason = _("Transaction too large for fee policy");
return false;
}
return true;
};
@ -3836,6 +3824,12 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
}
}
if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) {
// eventually allow a fallback fee
strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
return false;
}
if (nAmountLeft == nFeeRet) {
// We either added the change amount to nFeeRet because the change amount was considered
// to be dust or the input exactly matches output + fee.
@ -3894,6 +3888,11 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
tx = MakeTransactionRef(std::move(txNew));
}
if (nFeeRet > m_default_max_tx_fee) {
strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
return false;
}
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
if (!chain().checkChainLimits(tx)) {
@ -5094,8 +5093,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletInstance->m_min_fee = CFeeRate(n);
}
// TODO: enable when IsFallbackFeeEnabled is backported
// walletInstance->m_allow_fallback_fee = Params().IsFallbackFeeEnabled();
walletInstance->m_allow_fallback_fee = Params().IsTestChain();
if (gArgs.IsArgSet("-fallbackfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) {
@ -5508,7 +5506,7 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn)
fInternal = fInternalIn;
}
void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
void CWalletTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
{
// Update the tx's hashBlock
hashBlock = block_hash;
@ -5517,7 +5515,7 @@ void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
nIndex = posInBlock;
}
int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
int CWalletTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
{
if (hashUnset())
return 0;
@ -5525,7 +5523,7 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
}
bool CMerkleTx::IsLockedByInstantSend() const
bool CWalletTx::IsLockedByInstantSend() const
{
if (fIsChainlocked) {
fIsInstantSendLocked = false;
@ -5535,7 +5533,7 @@ bool CMerkleTx::IsLockedByInstantSend() const
return fIsInstantSendLocked;
}
bool CMerkleTx::IsChainLocked() const
bool CWalletTx::IsChainLocked() const
{
if (!fIsChainlocked) {
AssertLockHeld(cs_main);
@ -5547,7 +5545,7 @@ bool CMerkleTx::IsChainLocked() const
return fIsChainlocked;
}
int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
int CWalletTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
{
if (!IsCoinBase())
return 0;
@ -5556,7 +5554,7 @@ int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
}
bool CMerkleTx::IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const
bool CWalletTx::IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const
{
// note GetBlocksToMaturity is 0 for non-coinbase tx
return GetBlocksToMaturity(locked_chain) > 0;

View File

@ -12,7 +12,6 @@
#include <interfaces/handler.h>
#include <policy/feerate.h>
#include <saltedhasher.h>
#include <streams.h>
#include <script/ismine.h>
#include <tinyformat.h>
#include <ui_interface.h>
@ -226,82 +225,24 @@ struct COutputEntry
int vout;
};
/** A transaction with a merkle branch linking it to the block chain. */
/** Legacy class used for deserializing vtxPrev for backwards compatibility.
* vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3,
* but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs.
* These need to get deserialized for field alignment when deserializing
* a CWalletTx, but the deserialized values are discarded.**/
class CMerkleTx
{
private:
/** Constant used in hashBlock to indicate tx has been abandoned */
static const uint256 ABANDON_HASH;
mutable bool fIsChainlocked{false};
mutable bool fIsInstantSendLocked{false};
public:
CTransactionRef tx;
uint256 hashBlock;
/* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest
* block in the chain we know this or any in-wallet dependency conflicts
* with. Older clients interpret nIndex == -1 as unconfirmed for backward
* compatibility.
*/
int nIndex;
CMerkleTx()
template<typename Stream>
void Unserialize(Stream& s)
{
SetTx(MakeTransactionRef());
Init();
CTransactionRef tx;
uint256 hashBlock;
std::vector<uint256> vMerkleBranch;
int nIndex;
s >> tx >> hashBlock >> vMerkleBranch >> nIndex;
}
explicit CMerkleTx(CTransactionRef arg)
{
SetTx(std::move(arg));
Init();
}
void Init()
{
hashBlock = uint256();
nIndex = -1;
}
void SetTx(CTransactionRef arg)
{
tx = std::move(arg);
}
SERIALIZE_METHODS(CMerkleTx, obj)
{
std::vector<uint256> vMerkleBranch; // For compatibility with older versions.
READWRITE(obj.tx, obj.hashBlock, vMerkleBranch, obj.nIndex);
}
void SetMerkleBranch(const uint256& block_hash, int posInBlock);
/**
* Return depth of transaction in blockchain:
* <0 : conflicts with a transaction this deep in the blockchain
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
int GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const;
bool IsInMainChain(interfaces::Chain::Lock& locked_chain) const { return GetDepthInMainChain(locked_chain) > 0; }
bool IsLockedByInstantSend() const;
bool IsChainLocked() const;
/**
* @return number of blocks to maturity for this transaction:
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
* >0 : is a coinbase transaction which matures in this many blocks
*/
int GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const;
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const;
};
//Get the marginal bytes of spending the specified output
@ -311,11 +252,17 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet,
* A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain.
*/
class CWalletTx : public CMerkleTx
class CWalletTx
{
private:
const CWallet* pwallet;
/** Constant used in hashBlock to indicate tx has been abandoned */
static const uint256 ABANDON_HASH;
mutable bool fIsChainlocked{false};
mutable bool fIsInstantSendLocked{false};
public:
/**
* Key/value map with information about the transaction.
@ -373,7 +320,10 @@ public:
mutable bool fInMempool;
mutable CAmount nChangeCached;
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg)
: tx(std::move(arg)),
hashBlock(uint256()),
nIndex(-1)
{
Init(pwalletIn);
}
@ -393,10 +343,18 @@ public:
nOrderPos = -1;
}
CTransactionRef tx;
uint256 hashBlock;
/* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest
* block in the chain we know this or any in-wallet dependency conflicts
* with. Older clients interpret nIndex == -1 as unconfirmed for backward
* compatibility.
*/
int nIndex;
template<typename Stream>
void Serialize(Stream& s) const
{
char fSpent = false;
mapValue_t mapValueCopy = mapValue;
mapValueCopy["fromaccount"] = "";
@ -405,20 +363,21 @@ public:
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
}
s << static_cast<const CMerkleTx&>(*this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << fSpent;
std::vector<char> dummy_vector1; //!< Used to be vMerkleBranch
std::vector<char> dummy_vector2; //!< Used to be vtxPrev
char dummy_char = false; //!< Used to be fSpent
s << tx << hashBlock << dummy_vector1 << nIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_char;
}
template<typename Stream>
void Unserialize(Stream& s)
{
Init(nullptr);
char fSpent;
s >> static_cast<CMerkleTx&>(*this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;
std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch
std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev
char dummy_char; //! Used to be fSpent
s >> tx >> hashBlock >> dummy_vector1 >> nIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_char;
ReadOrderPos(nOrderPos, mapValue);
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
@ -429,6 +388,11 @@ public:
mapValue.erase("timesmart");
}
void SetTx(CTransactionRef arg)
{
tx = std::move(arg);
}
//! make sure balances are recalculated
void MarkDirty()
{
@ -500,6 +464,33 @@ public:
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
// in place.
std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS;
void SetMerkleBranch(const uint256& block_hash, int posInBlock);
/**
* Return depth of transaction in blockchain:
* <0 : conflicts with a transaction this deep in the blockchain
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
int GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const;
bool IsInMainChain(interfaces::Chain::Lock& locked_chain) const { return GetDepthInMainChain(locked_chain) > 0; }
bool IsLockedByInstantSend() const;
bool IsChainLocked() const;
/**
* @return number of blocks to maturity for this transaction:
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
* >0 : is a coinbase transaction which matures in this many blocks
*/
int GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const;
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const;
};
struct WalletTxHasher

View File

@ -136,7 +136,7 @@ class AddressIndexTest(BitcoinTestFramework):
unspent = self.nodes[0].listunspent()
tx = CTransaction()
tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))]
tx.vout = [CTxOut(10, scriptPubKey), CTxOut(11, scriptPubKey)]
tx.vout = [CTxOut(10 * COIN, scriptPubKey), CTxOut(11 * COIN, scriptPubKey)]
tx.rehash()
signed_tx = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())
@ -152,7 +152,7 @@ class AddressIndexTest(BitcoinTestFramework):
# Check that balances are correct
self.log.info("Testing balances...")
balance0 = self.nodes[1].getaddressbalance("93bVhahvUKmQu8gu9g3QnPPa2cxFK98pMB")
assert_equal(balance0["balance"], 45 * 100000000 + 21)
assert_equal(balance0["balance"], (45 + 21) * 100000000)
# Check that balances are correct after spending
self.log.info("Testing balances after spending...")

View File

@ -21,7 +21,10 @@ NOT_FINAL_ERROR = "non-BIP68-final (code 64)"
class BIP68Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [[], ["-acceptnonstdtxn=0"]]
self.extra_args = [
["-acceptnonstdtxn=1"],
["-acceptnonstdtxn=0"],
]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

View File

@ -82,7 +82,7 @@ class FullBlockTest(BitcoinTestFramework):
# which causes RPC to hang, so we need to increase RPC timeouts
self.rpc_timeout = 180
# Must set '-dip3params=2000:2000' to create pre-dip3 blocks only
self.extra_args = [['-dip3params=2000:2000']]
self.extra_args = [['-dip3params=2000:2000', '-acceptnonstdtxn=1']] # This is a consensus block test, we don't care about tx policy
def setup_nodes(self):
self.add_nodes(self.num_nodes, self.extra_args)

View File

@ -59,7 +59,12 @@ def cltv_validate(node, tx, height):
class BIP65Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-whitelist=127.0.0.1', '-dip3params=9000:9000', '-par=1']] # Use only one script thread to get the exact reject reason for testing
self.extra_args = [[
'-whitelist=127.0.0.1',
'-dip3params=9000:9000',
'-par=1', # Use only one script thread to get the exact reject reason for testing
'-acceptnonstdtxn=1', # cltv_invalidate is nonstandard
]]
self.setup_clean_chain = True
self.rpc_timeout = 120

View File

@ -40,6 +40,11 @@ class ConfArgsTest(BitcoinTestFramework):
conf.write("wallet=foo\n")
self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Config setting for -wallet only applied on regtest network when in [regtest] section.')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('regtest=0\n') # mainnet
conf.write('acceptnonstdtxn=1\n')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('nono\n')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead')

View File

@ -19,6 +19,7 @@ DISABLED_OPCODE_ERROR = "non-mandatory-script-verify-flag (Attempted to use a di
class DIP0020ActivationTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [["-acceptnonstdtxn=1"]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@ -31,7 +32,7 @@ class DIP0020ActivationTest(BitcoinTestFramework):
utxos = self.node.listunspent()
assert len(utxos) > 0
# Send some coins to a P2SH address constructed using disabled opcodes
# Lock some coins using disabled opcodes
utxo = utxos[len(utxos) - 1]
value = int(satoshi_round(utxo["amount"] - self.relayfee) * COIN)
tx = CTransaction()

View File

@ -126,9 +126,9 @@ class EstimateFeeTest(BitcoinTestFramework):
self.num_nodes = 3
# mine non-standard txs (e.g. txs with "dust" outputs)
self.extra_args = [
["-maxorphantxsize=1000", "-whitelist=127.0.0.1"],
["-blockmaxsize=17000", "-maxorphantxsize=1000", "-whitelist=127.0.0.1"],
["-blockmaxsize=8000", "-maxorphantxsize=1000", "-whitelist=127.0.0.1"]
["-acceptnonstdtxn=1", "-maxorphantxsize=1000", "-whitelist=127.0.0.1"],
["-acceptnonstdtxn=1", "-blockmaxsize=17000", "-maxorphantxsize=1000", "-whitelist=127.0.0.1"],
["-acceptnonstdtxn=1", "-blockmaxsize=8000", "-maxorphantxsize=1000", "-whitelist=127.0.0.1"]
]
def skip_test_if_missing_module(self):

View File

@ -35,7 +35,7 @@ class MaxUploadTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-maxuploadtarget=200", "-blockmaxsize=999000", "-maxtipage="+str(2*60*60*24*7)]]
self.extra_args = [["-maxuploadtarget=200", "-blockmaxsize=999000", "-maxtipage="+str(2*60*60*24*7), "-acceptnonstdtxn=1"]]
# Cache for utxos, as the listunspent may take a long time later in the test
self.utxo_cache = []

View File

@ -38,7 +38,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.extra_args = [[
'-txindex',
'-reindex', # Need reindex for txindex
'-acceptnonstdtxn=0', # Try to mimic main-net
]] * self.num_nodes
def skip_test_if_missing_module(self):

View File

@ -13,7 +13,11 @@ class MempoolLimitTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]]
self.extra_args = [[
"-acceptnonstdtxn=1",
"-maxmempool=5",
"-spendzeroconfchange=0",
]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

View File

@ -12,7 +12,10 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [["-printpriority=1"]] * 2
self.extra_args = [[
"-printpriority=1",
"-acceptnonstdtxn=1",
]] * self.num_nodes
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

View File

@ -93,7 +93,10 @@ class CompactBlocksTest(BitcoinTestFramework):
self.setup_clean_chain = True
# both nodes has the same version
self.num_nodes = 2
self.extra_args = [["-txindex"]] * 2
self.extra_args = [[
"-txindex",
"-acceptnonstdtxn=1",
]] * 2
self.utxos = []
def skip_test_if_missing_module(self):

View File

@ -27,6 +27,9 @@ class InvalidTxRequestTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [[
"-acceptnonstdtxn=1",
]]
self.setup_clean_chain = True
def bootstrap_p2p(self, *, num_connections=1):
@ -100,7 +103,7 @@ class InvalidTxRequestTest(BitcoinTestFramework):
self.test_orphan_tx_handling(block1.vtx[0].sha256, False)
self.log.info('Test orphan transaction handling, resolve via block')
self.restart_node(0, ['-persistmempool=0'])
self.restart_node(0, ["-acceptnonstdtxn=1", '-persistmempool=0'])
self.reconnect_p2p(num_connections=2)
self.test_orphan_tx_handling(block2.vtx[0].sha256, True)

View File

@ -42,11 +42,11 @@ class RawTransactionsTest(BitcoinTestFramework):
connect_nodes(self.nodes[0], 3)
def run_test(self):
min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
self.min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
node.settxfee(min_relay_tx_fee)
node.settxfee(self.min_relay_tx_fee)
# if the fee's positive delta is higher than this value tests will fail,
# neg. delta always fail the tests.
@ -54,13 +54,42 @@ class RawTransactionsTest(BitcoinTestFramework):
# than a minimum sized signature.
# = 2 bytes * minRelayTxFeePerByte
feeTolerance = 2 * min_relay_tx_fee/1000
self.fee_tolerance = 2 * self.min_relay_tx_fee / 1000
self.nodes[2].generate(1)
self.sync_all()
self.nodes[0].generate(121)
self.sync_all()
self.test_change_position()
self.test_simple()
self.test_simple_two_coins()
self.test_simple_two_outputs()
self.test_change()
self.test_no_change()
self.test_invalid_option()
self.test_invalid_change_address()
self.test_valid_change_address()
self.test_coin_selection()
self.test_two_vin()
self.test_two_vin_two_vout()
self.test_invalid_input()
self.test_fee_p2pkh()
self.test_fee_p2pkh_multi_out()
self.test_fee_p2sh()
self.test_fee_4of5()
self.test_spend_2of2()
self.test_locked_wallet()
self.test_many_inputs_fee()
self.test_many_inputs_send()
self.test_op_return()
self.test_watchonly()
self.test_all_watched_funds()
self.test_option_feerate()
self.test_address_reuse()
self.test_option_subtract_fee_from_outputs()
def test_change_position(self):
# ensure that setting changePosition in fundraw with an exact match is handled properly
rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():500})
rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {"changePosition":1, "subtractFeeFromOutputs":[0]})
@ -68,15 +97,15 @@ class RawTransactionsTest(BitcoinTestFramework):
watchonly_address = self.nodes[0].getnewaddress()
watchonly_pubkey = self.nodes[0].getaddressinfo(watchonly_address)["pubkey"]
watchonly_amount = Decimal(2000)
self.watchonly_amount = Decimal(2000)
self.nodes[3].importpubkey(watchonly_pubkey, "", True)
watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount)
self.watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, self.watchonly_amount)
# Lock UTXO so nodes[0] doesn't accidentally spend it
watchonly_vout = find_vout_for_address(self.nodes[0], watchonly_txid, watchonly_address)
self.nodes[0].lockunspent(False, [{"txid": watchonly_txid, "vout": watchonly_vout}])
self.watchonly_vout = find_vout_for_address(self.nodes[0], self.watchonly_txid, watchonly_address)
self.nodes[0].lockunspent(False, [{"txid": self.watchonly_txid, "vout": self.watchonly_vout}])
self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10)
self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), self.watchonly_amount / 10)
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 15)
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
@ -85,6 +114,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
def test_simple(self):
###############
# simple test #
###############
@ -93,10 +123,10 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
assert len(dec_tx['vin']) > 0 #test that we have enough inputs
def test_simple_two_coins(self):
##############################
# simple test with two coins #
##############################
@ -106,25 +136,11 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
assert len(dec_tx['vin']) > 0 #test if we have enough inputs
##############################
# simple test with two coins #
##############################
inputs = [ ]
outputs = { self.nodes[0].getnewaddress() : 26 }
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
assert len(dec_tx['vin']) > 0
assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')
def test_simple_two_outputs(self):
################################
# simple test with two outputs #
################################
@ -134,7 +150,6 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
for out in dec_tx['vout']:
@ -143,7 +158,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert len(dec_tx['vin']) > 0
assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')
def test_change(self):
#########################################################################
# test a fundrawtransaction with a VIN greater than the required amount #
#########################################################################
@ -157,6 +172,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
self.test_no_change_fee = fee # Use the same fee for the next tx
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
for out in dec_tx['vout']:
@ -164,14 +180,14 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee
def test_no_change(self):
#####################################################################
# test a fundrawtransaction with which will not get a change output #
#####################################################################
utx = get_unspent(self.nodes[2].listunspent(), 50)
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
outputs = { self.nodes[0].getnewaddress() : Decimal(50) - fee - feeTolerance }
outputs = {self.nodes[0].getnewaddress(): Decimal(50) - self.test_no_change_fee - self.fee_tolerance}
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
@ -186,7 +202,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(rawtxfund['changepos'], -1)
assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee
def test_invalid_option(self):
####################################################
# test a fundrawtransaction with an invalid option #
####################################################
@ -203,6 +219,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# reserveChangeKey was deprecated and is now removed
assert_raises_rpc_error(-3, "Unexpected key reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, options={'reserveChangeKey': True}))
def test_invalid_change_address(self):
############################################################
# test a fundrawtransaction with an invalid change address #
############################################################
@ -216,6 +233,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-5, "changeAddress must be a valid dash address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
def test_valid_change_address(self):
############################################################
# test a fundrawtransaction with a provided change address #
############################################################
@ -234,7 +252,7 @@ class RawTransactionsTest(BitcoinTestFramework):
out = dec_tx['vout'][0]
assert_equal(change, out['scriptPubKey']['addresses'][0])
def test_coin_selection(self):
#########################################################################
# test a fundrawtransaction with a VIN smaller than the required amount #
#########################################################################
@ -252,7 +270,6 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
matchingOuts = 0
@ -269,7 +286,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(matchingOuts, 1)
assert_equal(len(dec_tx['vout']), 2)
def test_two_vin(self):
###########################################
# test a fundrawtransaction with two VINs #
###########################################
@ -283,7 +300,6 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
matchingOuts = 0
@ -303,6 +319,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params
def test_two_vin_two_vout(self):
#########################################################
# test a fundrawtransaction with two VINs and two vOUTs #
#########################################################
@ -316,7 +333,6 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
matchingOuts = 0
@ -328,16 +344,16 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(matchingOuts, 2)
assert_equal(len(dec_tx['vout']), 3)
def test_invalid_input(self):
##############################################
# test a fundrawtransaction with invalid vin #
##############################################
inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin!
outputs = { self.nodes[0].getnewaddress() : 10}
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx)
def test_fee_p2pkh(self):
############################################################
#compare fee of a standard pubkeyhash transaction
inputs = []
@ -351,9 +367,10 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= feeTolerance
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
############################################################
def test_fee_p2pkh_multi_out(self):
############################################################
#compare fee of a standard pubkeyhash transaction with multiple outputs
inputs = []
@ -366,10 +383,10 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= feeTolerance
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
############################################################
def test_fee_p2sh(self):
############################################################
#compare fee of a 2of2 multisig p2sh transaction
@ -393,10 +410,10 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= feeTolerance
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
############################################################
def test_fee_4of5(self):
############################################################
#compare fee of a standard pubkeyhash transaction
@ -426,10 +443,10 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= feeTolerance
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
############################################################
def test_spend_2of2(self):
############################################################
# spend a 2of2 multisig transaction over fundraw
@ -444,7 +461,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# send 12 DASH to msig addr
txId = self.nodes[0].sendtoaddress(mSigObj, 12)
self.nodes[0].sendtoaddress(mSigObj, 12)
self.sync_all()
self.nodes[1].generate(1)
self.sync_all()
@ -456,7 +473,7 @@ class RawTransactionsTest(BitcoinTestFramework):
fundedTx = self.nodes[2].fundrawtransaction(rawtx)
signedTx = self.nodes[2].signrawtransactionwithwallet(fundedTx['hex'])
txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
self.nodes[2].sendrawtransaction(signedTx['hex'])
self.sync_all()
self.nodes[1].generate(1)
self.sync_all()
@ -464,6 +481,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# make sure funds are received at node1
assert_equal(oldBalance+Decimal('11.0000000'), self.nodes[1].getbalance())
def test_locked_wallet(self):
############################################################
# locked wallet test
self.nodes[1].encryptwallet("test")
@ -473,7 +491,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
node.settxfee(min_relay_tx_fee)
node.settxfee(self.min_relay_tx_fee)
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 2)
@ -481,7 +499,7 @@ class RawTransactionsTest(BitcoinTestFramework):
connect_nodes(self.nodes[0], 3)
# Again lock the watchonly UTXO or nodes[0] may spend it, because
# lockunspent is memory-only and thus lost on restart
self.nodes[0].lockunspent(False, [{"txid": watchonly_txid, "vout": watchonly_vout}])
self.nodes[0].lockunspent(False, [{"txid": self.watchonly_txid, "vout": self.watchonly_vout}])
self.sync_all()
# drain the keypool
@ -509,13 +527,14 @@ class RawTransactionsTest(BitcoinTestFramework):
#now we need to unlock
self.nodes[1].walletpassphrase("test", 600)
signedTx = self.nodes[1].signrawtransactionwithwallet(fundedTx['hex'])
txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
self.nodes[1].sendrawtransaction(signedTx['hex'])
self.nodes[1].generate(1)
self.sync_all()
# make sure funds are received at node1
assert_equal(oldBalance+Decimal('511.0000000'), self.nodes[0].getbalance())
def test_many_inputs_fee(self):
###############################################
# multiple (~19) inputs tx test | Compare fee #
###############################################
@ -543,9 +562,9 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= feeTolerance*19 #~19 inputs
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance * 19 #~19 inputs
def test_many_inputs_send(self):
#############################################
# multiple (~19) inputs tx test | sign/send #
#############################################
@ -569,12 +588,13 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
fundedTx = self.nodes[1].fundrawtransaction(rawtx)
fundedAndSignedTx = self.nodes[1].signrawtransactionwithwallet(fundedTx['hex'])
txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
assert_equal(oldBalance+Decimal('500.19000000'), self.nodes[0].getbalance()) #0.19+block reward
def test_op_return(self):
#####################################################
# test fundrawtransaction with OP_RETURN and no vin #
#####################################################
@ -591,40 +611,41 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_greater_than(len(dec_tx['vin']), 0) # at least one vin
assert_equal(len(dec_tx['vout']), 2) # one change output added
def test_watchonly(self):
##################################################
# test a fundrawtransaction using only watchonly #
##################################################
inputs = []
outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2}
outputs = {self.nodes[2].getnewaddress(): self.watchonly_amount / 2}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
result = self.nodes[3].fundrawtransaction(rawtx, {'includeWatching': True })
res_dec = self.nodes[0].decoderawtransaction(result["hex"])
assert_equal(len(res_dec["vin"]), 1)
assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)
assert_equal(res_dec["vin"][0]["txid"], self.watchonly_txid)
assert "fee" in result.keys()
assert_greater_than(result["changepos"], -1)
def test_all_watched_funds(self):
###############################################################
# test fundrawtransaction using the entirety of watched funds #
###############################################################
inputs = []
outputs = {self.nodes[2].getnewaddress() : watchonly_amount}
outputs = {self.nodes[2].getnewaddress(): self.watchonly_amount}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
# Backward compatibility test (2nd param is includeWatching)
result = self.nodes[3].fundrawtransaction(rawtx, True)
res_dec = self.nodes[0].decoderawtransaction(result["hex"])
assert_equal(len(res_dec["vin"]), 2)
assert res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid
assert res_dec["vin"][0]["txid"] == self.watchonly_txid or res_dec["vin"][1]["txid"] == self.watchonly_txid
assert_greater_than(result["fee"], 0)
assert_greater_than(result["changepos"], -1)
assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10)
assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], self.watchonly_amount / 10)
signedtx = self.nodes[3].signrawtransactionwithwallet(result["hex"])
assert not signedtx["complete"]
@ -634,6 +655,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
def test_option_feerate(self):
#######################
# Test feeRate option #
#######################
@ -644,18 +666,20 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {self.nodes[3].getnewaddress() : 1}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee})
result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10*min_relay_tx_fee})
result = self.nodes[3].fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee})
result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10 * self.min_relay_tx_fee})
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1})
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
def test_address_reuse(self):
################################
# Test no address reuse occurs #
################################
rawtx = self.nodes[3].createrawtransaction(inputs=[], outputs={self.nodes[3].getnewaddress(): 1})
result3 = self.nodes[3].fundrawtransaction(rawtx)
res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
changeaddress = ""
@ -667,6 +691,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Now the change address key should be removed from the keypool
assert changeaddress != nextaddr
def test_option_subtract_fee_from_outputs(self):
######################################
# Test subtractFeeFromOutputs option #
######################################
@ -678,11 +703,11 @@ class RawTransactionsTest(BitcoinTestFramework):
outputs = {self.nodes[2].getnewaddress(): 1}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
result = [self.nodes[3].fundrawtransaction(rawtx), # uses min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}),
self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee, "subtractFeeFromOutputs": [0]})]
result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses self.min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee}),
self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee, "subtractFeeFromOutputs": [0]}),]
dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result]
output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]

View File

@ -203,6 +203,7 @@ BASE_SCRIPTS = [
'feature_governance_objects.py',
'rpc_uptime.py',
'wallet_resendwallettransactions.py',
'wallet_fallbackfee.py',
'feature_minchainwork.py',
'p2p_unrequested_blocks.py', # NOTE: needs dash_hash to pass
'feature_shutdown.py',

View File

@ -4,20 +4,23 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet balance RPC methods."""
from decimal import Decimal
import struct
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE as ADDRESS_WATCHONLY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
connect_nodes,
sync_blocks,
)
RANDOM_COINBASE_ADDRESS = 'ycwedq2f3sz2Yf9JqZsBCQPxp18WU3Hp4J'
def create_transactions(node, address, amt, fees):
# Create and sign raw transactions from node to address for amt.
# Creates a transaction for each fee and returns an array
# of the raw transactions.
utxos = node.listunspent(0)
utxos = [u for u in node.listunspent(0) if u['spendable']]
# Create transactions
inputs = []
@ -25,14 +28,20 @@ def create_transactions(node, address, amt, fees):
for utxo in utxos:
inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
ins_total += utxo['amount']
if ins_total > amt:
if ins_total >= amt + max(fees):
break
# make sure there was enough utxos
assert ins_total >= amt + max(fees)
txs = []
for fee in fees:
outputs = {address: amt, node.getrawchangeaddress(): ins_total - amt - fee}
outputs = {address: amt}
# prevent 0 change output
if ins_total > amt + fee:
outputs[node.getrawchangeaddress()] = ins_total - amt - fee
raw_tx = node.createrawtransaction(inputs, outputs, 0)
raw_tx = node.signrawtransactionwithwallet(raw_tx)
assert_equal(raw_tx['complete'], True)
txs.append(raw_tx)
return txs
@ -41,21 +50,26 @@ class WalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [
['-limitdescendantcount=3'], # Limit mempool descendants as a hack to have wallet txs rejected from the mempool
[],
]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
self.nodes[0].importaddress(ADDRESS_WATCHONLY)
# Check that nodes don't own any UTXOs
assert_equal(len(self.nodes[0].listunspent()), 0)
assert_equal(len(self.nodes[1].listunspent()), 0)
self.log.info("Mining one block for each node")
self.log.info("Mining blocks ...")
self.nodes[0].generate(1)
self.sync_all()
self.nodes[1].generate(1)
self.nodes[1].generatetoaddress(100, RANDOM_COINBASE_ADDRESS)
self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
self.sync_all()
assert_equal(self.nodes[0].getbalance(), 500)
@ -66,6 +80,8 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getbalance("*", 1), 500)
assert_equal(self.nodes[0].getbalance("*", 1, True), 500)
assert_equal(self.nodes[0].getbalance(minconf=1), 500)
assert_equal(self.nodes[0].getbalance(minconf=0, include_watchonly=True), 1000)
assert_equal(self.nodes[1].getbalance(minconf=0, include_watchonly=True), 500)
# Send 490 BTC from 0 to 1 and 960 BTC from 1 to 0.
txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 490 , [Decimal('0.01')])
@ -83,32 +99,34 @@ class WalletTest(BitcoinTestFramework):
self.log.info("Test getbalance and getunconfirmedbalance with unconfirmed inputs")
# getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions
assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send
assert_equal(self.nodes[1].getbalance(), Decimal('29.99')) # change from node 1's send
# Same with minconf=0
assert_equal(self.nodes[0].getbalance(minconf=0), Decimal('9.99'))
assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('29.99'))
# getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
# TODO: fix getbalance tracking of coin spentness depth
assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0'))
assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
# getunconfirmedbalance
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('960')) # output of node 1's spend
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
def test_balances(*, fee_node_1=0):
# getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions
assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send
assert_equal(self.nodes[1].getbalance(), Decimal('30') - fee_node_1) # change from node 1's send
# Same with minconf=0
assert_equal(self.nodes[0].getbalance(minconf=0), Decimal('9.99'))
assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('30') - fee_node_1)
# getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
# TODO: fix getbalance tracking of coin spentness depth
assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0'))
assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
# getunconfirmedbalance
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('960')) # output of node 1's spend
assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('960'))
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0'))
test_balances(fee_node_1=Decimal('0.01'))
# Node 1 bumps the transaction fee and resends
# self.nodes[1].sendrawtransaction(txs[1]['hex']) # disabled, no RBF in Dash
#self.nodes[0].sendrawtransaction(txs[1]['hex']) # sending on both nodes is faster than waiting for propagation # disabled, no RBF in Dash
self.sync_all()
self.log.info("Test getbalance and getunconfirmedbalance with conflicted unconfirmed inputs")
# test_balances(fee_node_1=Decimal('0.02'))
assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('960')) # output of node 1's send
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('960'))
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0')) # Doesn't include output of node 0's send since it was spent
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0'))
self.nodes[1].generatetoaddress(1, RANDOM_COINBASE_ADDRESS)
self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)
self.sync_all()
# balances are correct after the transactions are confirmed
@ -118,7 +136,7 @@ class WalletTest(BitcoinTestFramework):
# Send total balance away from node 1
txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), Decimal('29.98'), [Decimal('0.01')])
self.nodes[1].sendrawtransaction(txs[0]['hex'])
self.nodes[1].generatetoaddress(2, RANDOM_COINBASE_ADDRESS)
self.nodes[1].generatetoaddress(2, ADDRESS_WATCHONLY)
self.sync_all()
# getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
@ -140,6 +158,52 @@ class WalletTest(BitcoinTestFramework):
after = self.nodes[1].getunconfirmedbalance()
assert_equal(before + Decimal('0.1'), after)
# Create 3 more wallet txs, where the last is not accepted to the
# mempool because it is the third descendant of the tx above
for _ in range(3):
# Set amount high enough such that all coins are spent by each tx
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 999)
self.log.info('Check that wallet txs not in the mempool are untrusted')
assert txid not in self.nodes[0].getrawmempool()
assert_equal(self.nodes[0].gettransaction(txid)['trusted'], False)
assert_equal(self.nodes[0].getbalance(minconf=0), 0)
self.log.info("Test replacement and reorg of non-mempool tx")
tx_orig = self.nodes[0].gettransaction(txid)['hex']
# Increase fee by 1 coin
tx_replace = tx_orig.replace(
struct.pack("<q", 999 * 10**8).hex(),
struct.pack("<q", 998 * 10**8).hex(),
)
tx_replace = self.nodes[0].signrawtransactionwithwallet(tx_replace)['hex']
# Total balance is given by the sum of outputs of the tx
total_amount = sum([o['value'] for o in self.nodes[0].decoderawtransaction(tx_replace)['vout']])
self.sync_all()
self.nodes[1].sendrawtransaction(hexstring=tx_replace, maxfeerate=0)
# Now confirm tx_replace
block_reorg = self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)[0]
self.sync_all()
assert_equal(self.nodes[0].getbalance(minconf=0), total_amount)
self.log.info('Put txs back into mempool of node 1 (not node 0)')
self.nodes[0].invalidateblock(block_reorg)
self.nodes[1].invalidateblock(block_reorg)
assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
self.nodes[0].generatetoaddress(1, ADDRESS_WATCHONLY)
assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
# Now confirm tx_orig
self.restart_node(1, ['-persistmempool=0', '-checklevel=0'])
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 0)
sync_blocks(self.nodes)
self.nodes[1].sendrawtransaction(tx_orig)
self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)
self.sync_all()
assert_equal(self.nodes[0].getbalance(minconf=0), total_amount + 1) # The reorg recovered our fee of 1 coin
if __name__ == '__main__':
WalletTest().main()

View File

@ -21,8 +21,11 @@ from test_framework.util import (
class WalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.extra_args = [[
"-acceptnonstdtxn=1",
'-usehd={:d}'.format(i%2==0),
] for i in range(self.num_nodes)]
self.setup_clean_chain = True
self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

View File

@ -6,6 +6,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
@ -18,6 +19,10 @@ class CreateTxWalletTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def run_test(self):
self.test_anti_fee_sniping()
self.test_tx_size_too_large()
def test_anti_fee_sniping(self):
self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
self.bump_mocktime(8 * 60 * 60 + 1)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
@ -31,6 +36,40 @@ class CreateTxWalletTest(BitcoinTestFramework):
tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
assert 0 < tx['locktime'] <= 201
def test_tx_size_too_large(self):
# More than 10kB of outputs, so that we hit -maxtxfee with a high feerate
outputs = {self.nodes[0].getnewaddress(): 0.000025 for i in range(400)}
raw_tx = self.nodes[0].createrawtransaction(inputs=[], outputs=outputs)
for fee_setting in ['-minrelaytxfee=0.01', '-mintxfee=0.01', '-paytxfee=0.01']:
self.log.info('Check maxtxfee in combination with {}'.format(fee_setting))
self.restart_node(0, extra_args=[fee_setting])
assert_raises_rpc_error(
-6,
"Fee exceeds maximum configured by -maxtxfee",
lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
)
assert_raises_rpc_error(
-4,
"Fee exceeds maximum configured by -maxtxfee",
lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
)
self.log.info('Check maxtxfee in combination with settxfee')
self.restart_node(0)
self.nodes[0].settxfee(0.01)
assert_raises_rpc_error(
-6,
"Fee exceeds maximum configured by -maxtxfee",
lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
)
assert_raises_rpc_error(
-4,
"Fee exceeds maximum configured by -maxtxfee",
lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
)
self.nodes[0].settxfee(0)
if __name__ == '__main__':
CreateTxWalletTest().main()

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_raises_rpc_error
class WalletRBFTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
def run_test(self):
self.nodes[0].generate(101)
# sending a transaction without fee estimations must be possible by default on regtest
self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
# test sending a tx with disabled fallback fee (must fail)
self.restart_node(0, extra_args=["-fallbackfee=0"])
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].fundrawtransaction(self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})))
assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1}))
if __name__ == '__main__':
WalletRBFTest().main()