aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--contrib/guix/manifest.scm2
-rw-r--r--doc/README.md2
-rw-r--r--doc/design/assumeutxo.md (renamed from doc/assumeutxo.md)0
-rw-r--r--doc/design/libraries.md104
-rw-r--r--doc/design/multiprocess.md (renamed from doc/multiprocess.md)0
-rw-r--r--src/chain.h2
-rw-r--r--src/net.cpp2
-rw-r--r--src/qt/guiutil.cpp30
-rw-r--r--src/qt/guiutil.h8
-rw-r--r--src/qt/test/optiontests.cpp10
-rw-r--r--src/qt/test/optiontests.h1
-rw-r--r--src/qt/utilitydialog.cpp8
-rw-r--r--src/test/net_tests.cpp7
-rw-r--r--src/wallet/wallet.cpp15
-rw-r--r--src/wallet/wallet.h2
-rwxr-xr-xtest/functional/feature_fee_estimation.py1
-rwxr-xr-xtest/functional/feature_rbf.py1
-rwxr-xr-xtest/functional/mempool_unbroadcast.py2
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py2
-rwxr-xr-xtest/functional/p2p_segwit.py2
-rwxr-xr-xtest/functional/rpc_rawtransaction.py2
-rw-r--r--test/functional/test_framework/util.py5
-rw-r--r--test/functional/test_framework/wallet.py27
24 files changed, 179 insertions, 57 deletions
diff --git a/configure.ac b/configure.ac
index 94abb0dfec..163f69988e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,7 @@ BITCOIN_MP_NODE_NAME=bitcoin-node
BITCOIN_MP_GUI_NAME=bitcoin-gui
dnl Unless the user specified ARFLAGS, force it to be cr
+dnl This is also the default as-of libtool 2.4.7
AC_ARG_VAR([ARFLAGS], [Flags for the archiver, defaults to <cr> if not set])
if test "${ARFLAGS+set}" != "set"; then
ARFLAGS="cr"
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 34a9c608db..d35ad85e56 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -581,7 +581,7 @@ inspecting signatures in Mach-O binaries.")
xz
;; Build tools
gnu-make
- libtool
+ libtool-2.4.7
autoconf-2.71
automake
pkg-config
diff --git a/doc/README.md b/doc/README.md
index 33f71f4807..31c95afab0 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -64,6 +64,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
- [BIPS](bips.md)
- [Dnsseed Policy](dnsseed-policy.md)
- [Benchmarking](benchmarking.md)
+- [Internal Design Docs](design/)
### Resources
* Discuss on the [BitcoinTalk](https://bitcointalk.org/) forums, in the [Development & Technical Discussion board](https://bitcointalk.org/index.php?board=6.0).
@@ -71,7 +72,6 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
### Miscellaneous
- [Assets Attribution](assets-attribution.md)
-- [Assumeutxo design](assumeutxo.md)
- [bitcoin.conf Configuration File](bitcoin-conf.md)
- [CJDNS Support](cjdns.md)
- [Files](files.md)
diff --git a/doc/assumeutxo.md b/doc/design/assumeutxo.md
index 2726cf779b..2726cf779b 100644
--- a/doc/assumeutxo.md
+++ b/doc/design/assumeutxo.md
diff --git a/doc/design/libraries.md b/doc/design/libraries.md
new file mode 100644
index 0000000000..75f8d60ba0
--- /dev/null
+++ b/doc/design/libraries.md
@@ -0,0 +1,104 @@
+# Libraries
+
+| Name | Description |
+|--------------------------|-------------|
+| *libbitcoin_cli* | RPC client functionality used by *bitcoin-cli* executable |
+| *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). |
+| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet* and also exposed as a [shared library](../shared-libraries.md). |
+| *libbitcoinconsensus* | Shared library build of static *libbitcoin_consensus* library |
+| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node* and also exposed as a [shared library](../shared-libraries.md). |
+| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables |
+| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. |
+| *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. |
+| *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). |
+| *libbitcoin_wallet* | Wallet functionality used by *bitcoind* and *bitcoin-wallet* executables. |
+| *libbitcoin_wallet_tool* | Lower-level wallet functionality used by *bitcoin-wallet* executable. |
+| *libbitcoin_zmq* | [ZeroMQ](../zmq.md) functionality used by *bitcoind* and *bitcoin-qt* executables. |
+
+## Conventions
+
+- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. Exceptions are *libbitcoin_consensus* and *libbitcoin_kernel* which have external interfaces documented at [../shared-libraries.md](../shared-libraries.md).
+
+- Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`libbitcoin_*_SOURCES`](../../src/Makefile.am) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like:
+
+ - *libbitcoin_node* code lives in `src/node/` in the `node::` namespace
+ - *libbitcoin_wallet* code lives in `src/wallet/` in the `wallet::` namespace
+ - *libbitcoin_ipc* code lives in `src/ipc/` in the `ipc::` namespace
+ - *libbitcoin_util* code lives in `src/util/` in the `util::` namespace
+ - *libbitcoin_consensus* code lives in `src/consensus/` in the `Consensus::` namespace
+
+## Dependencies
+
+- Libraries should minimize what other libraries they depend on, and only reference symbols following the arrows shown in the dependency graph below:
+
+<table><tr><td>
+
+```mermaid
+
+%%{ init : { "flowchart" : { "curve" : "linear" }}}%%
+
+graph TD;
+
+bitcoin-cli[bitcoin-cli]-->libbitcoin_cli;
+
+bitcoind[bitcoind]-->libbitcoin_node;
+bitcoind[bitcoind]-->libbitcoin_wallet;
+
+bitcoin-qt[bitcoin-qt]-->libbitcoin_node;
+bitcoin-qt[bitcoin-qt]-->libbitcoinqt;
+bitcoin-qt[bitcoin-qt]-->libbitcoin_wallet;
+
+bitcoin-wallet[bitcoin-wallet]-->libbitcoin_wallet;
+bitcoin-wallet[bitcoin-wallet]-->libbitcoin_wallet_tool;
+
+libbitcoin_cli-->libbitcoin_common;
+libbitcoin_cli-->libbitcoin_util;
+
+libbitcoin_common-->libbitcoin_util;
+libbitcoin_common-->libbitcoin_consensus;
+
+libbitcoin_kernel-->libbitcoin_consensus;
+libbitcoin_kernel-->libbitcoin_util;
+
+libbitcoin_node-->libbitcoin_common;
+libbitcoin_node-->libbitcoin_consensus;
+libbitcoin_node-->libbitcoin_kernel;
+libbitcoin_node-->libbitcoin_util;
+
+libbitcoinqt-->libbitcoin_common;
+libbitcoinqt-->libbitcoin_util;
+
+libbitcoin_wallet-->libbitcoin_common;
+libbitcoin_wallet-->libbitcoin_util;
+
+libbitcoin_wallet_tool-->libbitcoin_util;
+libbitcoin_wallet_tool-->libbitcoin_wallet;
+
+classDef bold stroke-width:2px, font-weight:bold, font-size: smaller;
+class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold
+```
+</td></tr><tr><td>
+
+**Dependency graph**. Arrows show linker symbol dependencies. *Consensus* lib depends on nothing. *Util* lib is depended on by everything. *Kernel* lib depends only on consensus and util.
+
+</td></tr></table>
+
+- The graph shows what _linker symbols_ (functions and variables) from each library other libraries can call and reference directly, but it is not a call graph. For example, there is no arrow connecting *libbitcoin_wallet* and *libbitcoin_node* libraries, because these libraries are intended to be modular and not depend on each other's internal implementation details. But wallet code still is still able to call node code indirectly through the `interfaces::Chain` abstract class in [`interfaces/chain.h`](../../src/interfaces/chain.h) and node code calls wallet code through the `interfaces::ChainClient` and `interfaces::Chain::Notifications` abstract classes in the same file. In general, defining abstract classes in [`src/interfaces/`](../../src/interfaces/) can be a convenient way of avoiding unwanted direct dependencies or circular dependencies between libraries.
+
+- *libbitcoin_consensus* should be a standalone dependency that any library can depend on, and it should not depend on any other libraries itself.
+
+- *libbitcoin_util* should also be a standalone dependency that any library can depend on, and it should not depend on other internal libraries.
+
+- *libbitcoin_common* should serve a similar function as *libbitcoin_util* and be a place for miscellaneous code used by various daemon, GUI, and CLI applications and libraries to live. It should not depend on anything other than *libbitcoin_util* and *libbitcoin_consensus*. The boundary between _util_ and _common_ is a little fuzzy but historically _util_ has been used for more generic, lower-level things like parsing hex, and _common_ has been used for bitcoin-specific, higher-level things like parsing base58. The difference between util and common is mostly important because *libbitcoin_kernel* is not supposed to depend on *libbitcoin_common*, only *libbitcoin_util*. In general, if it is ever unclear whether it is better to add code to *util* or *common*, it is probably better to add it to *common* unless it is very generically useful or useful particularly to include in the kernel.
+
+
+- *libbitcoin_kernel* should only depend on *libbitcoin_util* and *libbitcoin_consensus*.
+
+- The only thing that should depend on *libbitcoin_kernel* internally should be *libbitcoin_node*. GUI and wallet libraries *libbitcoinqt* and *libbitcoin_wallet* in particular should not depend on *libbitcoin_kernel* and the unneeded functionality it would pull in, like block validation. To the extent that GUI and wallet code need scripting and signing functionality, they should be get able it from *libbitcoin_consensus*, *libbitcoin_common*, and *libbitcoin_util*, instead of *libbitcoin_kernel*.
+
+- GUI, node, and wallet code internal implementations should all be independent of each other, and the *libbitcoinqt*, *libbitcoin_node*, *libbitcoin_wallet* libraries should never reference each other's symbols. They should only call each other through [`src/interfaces/`](`../../src/interfaces/`) abstract interfaces.
+
+## Work in progress
+
+- Validation code is moving from *libbitcoin_node* to *libbitcoin_kernel* as part of [The libbitcoinkernel Project #24303](https://github.com/bitcoin/bitcoin/issues/24303)
+- Source code organization is discussed in general in [Library source code organization #15732](https://github.com/bitcoin/bitcoin/issues/15732)
diff --git a/doc/multiprocess.md b/doc/design/multiprocess.md
index e3f389a6d3..e3f389a6d3 100644
--- a/doc/multiprocess.md
+++ b/doc/design/multiprocess.md
diff --git a/src/chain.h b/src/chain.h
index 24b5026aba..ecc2ae732f 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -138,7 +138,7 @@ enum BlockStatus : uint32_t {
* If set, this indicates that the block index entry is assumed-valid.
* Certain diagnostics will be skipped in e.g. CheckBlockIndex().
* It almost certainly means that the block's full validation is pending
- * on a background chainstate. See `doc/assumeutxo.md`.
+ * on a background chainstate. See `doc/design/assumeutxo.md`.
*/
BLOCK_ASSUMED_VALID = 256,
};
diff --git a/src/net.cpp b/src/net.cpp
index d42f130af7..c05fa771ef 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -250,7 +250,7 @@ std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
if (pnode->IsInboundConn()) {
// For inbound connections, assume both the address and the port
// as seen from the peer.
- addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices};
+ addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices, addrLocal.nTime};
} else {
// For outbound connections, assume just the address as seen from
// the peer and leave the port in `addrLocal` as returned by
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 186ed4f644..2551be0af3 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -53,6 +53,7 @@
#include <QMouseEvent>
#include <QPluginLoader>
#include <QProgressDialog>
+#include <QRegularExpression>
#include <QScreen>
#include <QSettings>
#include <QShortcut>
@@ -289,6 +290,17 @@ QString getDefaultDataDirectory()
return PathToQString(GetDefaultDataDir());
}
+QString ExtractFirstSuffixFromFilter(const QString& filter)
+{
+ QRegularExpression filter_re(QStringLiteral(".* \\(\\*\\.(.*)[ \\)]"), QRegularExpression::InvertedGreedinessOption);
+ QString suffix;
+ QRegularExpressionMatch m = filter_re.match(filter);
+ if (m.hasMatch()) {
+ suffix = m.captured(1);
+ }
+ return suffix;
+}
+
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
@@ -306,13 +318,7 @@ QString getSaveFileName(QWidget *parent, const QString &caption, const QString &
/* Directly convert path to native OS path separators */
QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter));
- /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
- QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
- QString selectedSuffix;
- if(filter_re.exactMatch(selectedFilter))
- {
- selectedSuffix = filter_re.cap(1);
- }
+ QString selectedSuffix = ExtractFirstSuffixFromFilter(selectedFilter);
/* Add suffix if needed */
QFileInfo info(result);
@@ -354,14 +360,8 @@ QString getOpenFileName(QWidget *parent, const QString &caption, const QString &
if(selectedSuffixOut)
{
- /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
- QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
- QString selectedSuffix;
- if(filter_re.exactMatch(selectedFilter))
- {
- selectedSuffix = filter_re.cap(1);
- }
- *selectedSuffixOut = selectedSuffix;
+ *selectedSuffixOut = ExtractFirstSuffixFromFilter(selectedFilter);
+ ;
}
return result;
}
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index e38ac6026a..acbe415a91 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -123,6 +123,14 @@ namespace GUIUtil
*/
QString getDefaultDataDirectory();
+ /**
+ * Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...).
+ *
+ * @param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
+ * @return QString
+ */
+ QString ExtractFirstSuffixFromFilter(const QString& filter);
+
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
when no suffix is provided by the user.
diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp
index 3bd0af19ad..17ffeb220b 100644
--- a/src/qt/test/optiontests.cpp
+++ b/src/qt/test/optiontests.cpp
@@ -4,6 +4,7 @@
#include <init.h>
#include <qt/bitcoin.h>
+#include <qt/guiutil.h>
#include <qt/test/optiontests.h>
#include <test/util/setup_common.h>
#include <util/system.h>
@@ -122,3 +123,12 @@ void OptionTests::parametersInteraction()
QVERIFY(!settings.contains("fListen"));
gArgs.ClearPathCache();
}
+
+void OptionTests::extractFilter()
+{
+ QString filter = QString("Partially Signed Transaction (Binary) (*.psbt)");
+ QCOMPARE(GUIUtil::ExtractFirstSuffixFromFilter(filter), "psbt");
+
+ filter = QString("Image (*.png *.jpg)");
+ QCOMPARE(GUIUtil::ExtractFirstSuffixFromFilter(filter), "png");
+}
diff --git a/src/qt/test/optiontests.h b/src/qt/test/optiontests.h
index 286d785572..57ec8bd0f2 100644
--- a/src/qt/test/optiontests.h
+++ b/src/qt/test/optiontests.h
@@ -22,6 +22,7 @@ private Q_SLOTS:
void migrateSettings();
void integerGetArgBug();
void parametersInteraction();
+ void extractFilter();
private:
interfaces::Node& m_node;
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index e68095f8e5..4894cac905 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -22,7 +22,8 @@
#include <QCloseEvent>
#include <QLabel>
#include <QMainWindow>
-#include <QRegExp>
+#include <QRegularExpression>
+#include <QString>
#include <QTextCursor>
#include <QTextTable>
#include <QVBoxLayout>
@@ -44,9 +45,8 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
/// HTML-format the license message from the core
QString licenseInfoHTML = QString::fromStdString(LicenseInfo());
// Make URLs clickable
- QRegExp uri("<(.*)>", Qt::CaseSensitive, QRegExp::RegExp2);
- uri.setMinimal(true); // use non-greedy matching
- licenseInfoHTML.replace(uri, "<a href=\"\\1\">\\1</a>");
+ QRegularExpression uri(QStringLiteral("<(.*)>"), QRegularExpression::InvertedGreedinessOption);
+ licenseInfoHTML.replace(uri, QStringLiteral("<a href=\"\\1\">\\1</a>"));
// Replace newlines with HTML breaks
licenseInfoHTML.replace("\n", "<br>");
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index e7c01bd6d0..115c4b9b24 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -675,10 +675,13 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
const uint16_t bind_port = 20001;
m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
+ const uint32_t current_time = static_cast<uint32_t>(GetAdjustedTime());
+ SetMockTime(current_time);
+
// Our address:port as seen from the peer, completely different from the above.
in_addr peer_us_addr;
peer_us_addr.s_addr = htonl(0x02030405);
- const CAddress peer_us{CService{peer_us_addr, 20002}, NODE_NETWORK};
+ const CAddress peer_us{CService{peer_us_addr, 20002}, NODE_NETWORK, current_time};
// Create a peer with a routable IPv4 address (outbound).
in_addr peer_out_in_addr;
@@ -699,7 +702,7 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port.
auto chosen_local_addr = GetLocalAddrForPeer(&peer_out);
BOOST_REQUIRE(chosen_local_addr);
- const CService expected{peer_us_addr, bind_port};
+ const CAddress expected{CService{peer_us_addr, bind_port}, NODE_NETWORK, current_time};
BOOST_CHECK(*chosen_local_addr == expected);
// Create a peer with a routable IPv4 address (inbound).
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ea306183ef..d0b093bbb7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -663,16 +663,13 @@ void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid, Walle
}
-void CWallet::AddToSpends(const uint256& wtxid, WalletBatch* batch)
+void CWallet::AddToSpends(const CWalletTx& wtx, WalletBatch* batch)
{
- auto it = mapWallet.find(wtxid);
- assert(it != mapWallet.end());
- const CWalletTx& thisTx = it->second;
- if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
+ if (wtx.IsCoinBase()) // Coinbases don't spend anything!
return;
- for (const CTxIn& txin : thisTx.tx->vin)
- AddToSpends(txin.prevout, wtxid, batch);
+ for (const CTxIn& txin : wtx.tx->vin)
+ AddToSpends(txin.prevout, wtx.GetHash(), batch);
}
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
@@ -967,7 +964,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
wtx.nOrderPos = IncOrderPosNext(&batch);
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
- AddToSpends(hash, &batch);
+ AddToSpends(wtx, &batch);
}
if (!fInsertedNew)
@@ -1066,7 +1063,7 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
if (/* insertion took place */ ins.second) {
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
- AddToSpends(hash);
+ AddToSpends(wtx);
for (const CTxIn& txin : wtx.tx->vin) {
auto it = mapWallet.find(txin.prevout.hash);
if (it != mapWallet.end()) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index a75b6981e1..bf42b3da9e 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -262,7 +262,7 @@ private:
typedef std::multimap<COutPoint, uint256> TxSpends;
TxSpends mapTxSpends GUARDED_BY(cs_wallet);
void AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- void AddToSpends(const uint256& wtxid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void AddToSpends(const CWalletTx& wtx, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Add a transaction to the wallet, or update it. confirm.block_* should
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 422612a78e..ca21dd8a73 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -51,7 +51,6 @@ def small_txpuzzle_randfee(
if total_in <= amount + fee:
raise RuntimeError(f"Insufficient funds: need {amount + fee}, have {total_in}")
tx = wallet.create_self_transfer_multi(
- from_node=from_node,
utxos_to_spend=utxos_to_spend,
fee_per_output=0)
tx.vout[0].nValue = int((total_in - amount - fee) * COIN)
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 4c1e86e93d..738c6ea4af 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -473,7 +473,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# Now attempt to submit a tx that double-spends all the root tx inputs, which
# would invalidate `num_txs_invalidated` transactions.
double_tx = wallet.create_self_transfer_multi(
- from_node=normal_node,
utxos_to_spend=root_utxos,
fee_per_output=10_000_000, # absurdly high feerate
)
diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py
index 37ef4a9157..7587adc257 100755
--- a/test/functional/mempool_unbroadcast.py
+++ b/test/functional/mempool_unbroadcast.py
@@ -40,7 +40,7 @@ class MempoolUnbroadcastTest(BitcoinTestFramework):
wallet_tx_hsh = node.sendtoaddress(addr, 0.0001)
# generate a txn using sendrawtransaction
- txFS = self.wallet.create_self_transfer(from_node=node)
+ txFS = self.wallet.create_self_transfer()
rpc_tx_hsh = node.sendrawtransaction(txFS["hex"])
# check transactions are in unbroadcast using rpc
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index e0f2446b2d..fb3974c1d5 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -212,7 +212,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
assert x not in mempool
# Create a free transaction. Should be rejected.
- tx_res = self.wallet.create_self_transfer(from_node=self.nodes[0], fee_rate=0)
+ tx_res = self.wallet.create_self_transfer(fee_rate=0)
tx_hex = tx_res['hex']
tx_id = tx_res['txid']
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 89ddfd3bcf..952f1e5cc5 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1998,7 +1998,7 @@ class SegWitTest(BitcoinTestFramework):
def serialize(self):
return serialize_with_bogus_witness(self.tx)
- tx = self.wallet.create_self_transfer(from_node=self.nodes[0])['tx']
+ tx = self.wallet.create_self_transfer()['tx']
assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, hexstring=serialize_with_bogus_witness(tx).hex(), iswitness=True)
with self.nodes[0].assert_debug_log(['Unknown transaction optional data']):
self.test_node.send_and_ping(msg_bogus_tx(tx))
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index dee6d777af..26a5da85b7 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -285,7 +285,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Test a transaction with a large fee.
# Fee rate is 0.20000000 BTC/kvB
- tx = self.wallet.create_self_transfer(from_node=self.nodes[0], fee_rate=Decimal("0.20000000"))
+ tx = self.wallet.create_self_transfer(fee_rate=Decimal("0.20000000"))
# Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([tx['hex']])[0]
assert_equal(testres['allowed'], False)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 1c64fa4028..6a588275ea 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -527,9 +527,8 @@ def create_lots_of_big_transactions(mini_wallet, node, fee, tx_batch_size, txout
use_internal_utxos = utxos is None
for _ in range(tx_batch_size):
tx = mini_wallet.create_self_transfer(
- from_node=node,
- utxo_to_spend=None if use_internal_utxos else utxos.pop(),
- fee_rate=0,
+ utxo_to_spend=None if use_internal_utxos else utxos.pop(),
+ fee_rate=0,
)["tx"]
tx.vout[0].nValue -= fee_sats
tx.vout.extend(txouts)
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 7249e53676..1e154fbd44 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -180,10 +180,10 @@ class MiniWallet:
self._utxos = []
return utxos
- def send_self_transfer(self, **kwargs):
+ def send_self_transfer(self, *, from_node, **kwargs):
"""Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
tx = self.create_self_transfer(**kwargs)
- self.sendrawtransaction(from_node=kwargs['from_node'], tx_hex=tx['hex'])
+ self.sendrawtransaction(from_node=from_node, tx_hex=tx['hex'])
return tx
def send_to(self, *, from_node, scriptPubKey, amount, fee=1000):
@@ -198,14 +198,14 @@ class MiniWallet:
Returns a tuple (txid, n) referring to the created external utxo outpoint.
"""
- tx = self.create_self_transfer(from_node=from_node, fee_rate=0)["tx"]
+ tx = self.create_self_transfer(fee_rate=0)["tx"]
assert_greater_than_or_equal(tx.vout[0].nValue, amount + fee)
tx.vout[0].nValue -= (amount + fee) # change output -> MiniWallet
tx.vout.append(CTxOut(amount, scriptPubKey)) # arbitrary output -> to be returned
txid = self.sendrawtransaction(from_node=from_node, tx_hex=tx.serialize().hex())
return txid, 1
- def send_self_transfer_multi(self, **kwargs):
+ def send_self_transfer_multi(self, *, from_node, **kwargs):
"""
Create and send a transaction that spends the given UTXOs and creates a
certain number of outputs with equal amounts.
@@ -217,16 +217,18 @@ class MiniWallet:
- list of newly created UTXOs, ordered by vout index
"""
tx = self.create_self_transfer_multi(**kwargs)
- txid = self.sendrawtransaction(from_node=kwargs['from_node'], tx_hex=tx.serialize().hex())
+ txid = self.sendrawtransaction(from_node=from_node, tx_hex=tx.serialize().hex())
return {'new_utxos': [self.get_utxo(txid=txid, vout=vout) for vout in range(len(tx.vout))],
'txid': txid, 'hex': tx.serialize().hex(), 'tx': tx}
def create_self_transfer_multi(
- self, *, from_node,
- utxos_to_spend: Optional[List[dict]] = None,
- num_outputs=1,
- sequence=0,
- fee_per_output=1000):
+ self,
+ *,
+ utxos_to_spend: Optional[List[dict]] = None,
+ num_outputs=1,
+ sequence=0,
+ fee_per_output=1000,
+ ):
"""
Create and return a transaction that spends the given UTXOs and creates a
certain number of outputs with equal amounts.
@@ -234,7 +236,7 @@ class MiniWallet:
utxos_to_spend = utxos_to_spend or [self.get_utxo()]
# create simple tx template (1 input, 1 output)
tx = self.create_self_transfer(
- fee_rate=0, from_node=from_node,
+ fee_rate=0,
utxo_to_spend=utxos_to_spend[0], sequence=sequence)["tx"]
# duplicate inputs, witnesses and outputs
@@ -253,9 +255,8 @@ class MiniWallet:
o.nValue = outputs_value_total // num_outputs
return tx
- def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node=None, utxo_to_spend=None, locktime=0, sequence=0):
+ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), utxo_to_spend=None, locktime=0, sequence=0):
"""Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
- from_node = from_node or self._test_node
utxo_to_spend = utxo_to_spend or self.get_utxo()
if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE):
vsize = Decimal(104) # anyone-can-spend