Skip to content

Commit

Permalink
Merge #26878: [24.x] Backports
Browse files Browse the repository at this point in the history
784a754 wallet, rpc: Update migratewallet help text for encrypted wallets (Andrew Chow)
debcfe3 tests: Tests for migrating wallets by name, and providing passphrase (Andrew Chow)
ccc72fe wallet: Be able to unlock the wallet for migration (Andrew Chow)
50dd8b1 rpc: Allow users to specify wallet name for migratewallet (Andrew Chow)
648b062 wallet: Allow MigrateLegacyToDescriptor to take a wallet name (Andrew Chow)
ab3bd45 i2p: use consistent number of tunnels with i2pd and Java I2P (Vasil Dimov)
29cdf42 i2p: lower the number of tunnels for transient sessions (Vasil Dimov)
5027e93 i2p: reuse created I2P sessions if not used (Vasil Dimov)
a62c541 wallet: reuse change dest when recreating TX with avoidpartialspends (Matthew Zipkin)
64e7db6 Zero out wallet master key upon lock (John Moffett)
b7e242e Correctly limit overview transaction list (John Moffett)
cff6718 depends: fix systemtap download URL (fanquake)
7cf73df Add missing includes to fix gcc-13 compile error (MarcoFalke)
07397cd addrdb: Only call Serialize() once (Martin Zumsande)
91f83db hash: add HashedSourceWriter (Martin Zumsande)
5c824ac For feebump, ignore abandoned descendant spends (John Moffett)
428dcd5 wallet: Skip rescanning if wallet is more recent than tip (Andrew Chow)
cbcdafa test: wallet: check that labels are migrated to watchonly wallet (Sebastian Falbesoner)
342abfb wallet: fully migrate address book entries for watchonly/solvable wallets (Sebastian Falbesoner)

Pull request description:

  Backports:
  * #26595
  * #26675
  * #26679
  * #26761
  * #26837
  * #26909
  * #26924
  * #26944
  * bitcoin-core/gui#704
  * #27053
  * #27080

ACKs for top commit:
  instagibbs:
    ACK 784a754
  achow101:
    ACK 784a754
  hebasto:
    ACK 784a754, I've made backporting locally and got a diff between my branch and this PR as follows:

Tree-SHA512: 8ea84aa02d7907ff1e202e1302b441ce9ed2198bf383620ad40056a5d7e8ea88e1047abef0b92d85648016bf9b3195c974be3806ccebd85bef4f85c326869e43
  • Loading branch information
glozow committed Feb 27, 2023
2 parents 2b87e90 + 784a754 commit c8c85ca
Show file tree
Hide file tree
Showing 23 changed files with 447 additions and 95 deletions.
2 changes: 1 addition & 1 deletion depends/packages/systemtap.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package=systemtap
$(package)_version=4.7
$(package)_download_path=https://sourceware.org/systemtap/ftp/releases/
$(package)_download_path=https://sourceware.org/ftp/systemtap/releases/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=43a0a3db91aa4d41e28015b39a65e62059551f3cc7377ebf3a3a5ca7339e7b1f
$(package)_patches=remove_SDT_ASM_SECTION_AUTOGROUP_SUPPORT_check.patch
Expand Down
7 changes: 3 additions & 4 deletions src/addrdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ bool SerializeDB(Stream& stream, const Data& data)
{
// Write and commit header, data
try {
CHashWriter hasher(stream.GetType(), stream.GetVersion());
stream << Params().MessageStart() << data;
hasher << Params().MessageStart() << data;
stream << hasher.GetHash();
HashedSourceWriter hashwriter{stream};
hashwriter << Params().MessageStart() << data;
stream << hashwriter.GetHash();
} catch (const std::exception& e) {
return error("%s: Serialize or I/O error - %s", __func__, e.what());
}
Expand Down
3 changes: 1 addition & 2 deletions src/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1178,8 +1178,7 @@ void AddrMan::Unserialize(Stream& s_)
}

// explicit instantiation
template void AddrMan::Serialize(CHashWriter& s) const;
template void AddrMan::Serialize(CAutoFile& s) const;
template void AddrMan::Serialize(HashedSourceWriter<CAutoFile>& s) const;
template void AddrMan::Serialize(CDataStream& s) const;
template void AddrMan::Unserialize(CAutoFile& s);
template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
Expand Down
25 changes: 25 additions & 0 deletions src/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef BITCOIN_HASH_H
#define BITCOIN_HASH_H

#include <attributes.h>
#include <crypto/common.h>
#include <crypto/ripemd160.h>
#include <crypto/sha256.h>
Expand Down Expand Up @@ -199,6 +200,30 @@ class CHashVerifier : public CHashWriter
}
};

/** Writes data to an underlying source stream, while hashing the written data. */
template <typename Source>
class HashedSourceWriter : public CHashWriter
{
private:
Source& m_source;

public:
explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : CHashWriter{source.GetType(), source.GetVersion()}, m_source{source} {}

void write(Span<const std::byte> src)
{
m_source.write(src);
CHashWriter::write(src);
}

template <typename T>
HashedSourceWriter& operator<<(const T& obj)
{
::Serialize(*this, obj);
return *this;
}
};

/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Expand Down
7 changes: 5 additions & 2 deletions src/i2p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,9 @@ void Session::CreateIfNotCreatedAlready()
// in the reply in DESTINATION=.
const Reply& reply = SendRequestAndGetReply(
*sock,
strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7", session_id));
strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7 "
"inbound.quantity=1 outbound.quantity=1",
session_id));

m_private_key = DecodeI2PBase64(reply.Get("DESTINATION"));
} else {
Expand All @@ -395,7 +397,8 @@ void Session::CreateIfNotCreatedAlready()
const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));

SendRequestAndGetReply(*sock,
strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s "
"inbound.quantity=3 outbound.quantity=3",
session_id,
private_key_b64));
}
Expand Down
23 changes: 22 additions & 1 deletion src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ static CAddress GetBindAddress(const Sock& sock)

CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type)
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);

if (pszDest == nullptr) {
Expand Down Expand Up @@ -496,8 +497,23 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (m_i2p_sam_session) {
connected = m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed);
} else {
i2p_transient_session = std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
{
LOCK(m_unused_i2p_sessions_mutex);
if (m_unused_i2p_sessions.empty()) {
i2p_transient_session =
std::make_unique<i2p::sam::Session>(proxy.proxy, &interruptNet);
} else {
i2p_transient_session.swap(m_unused_i2p_sessions.front());
m_unused_i2p_sessions.pop();
}
}
connected = i2p_transient_session->Connect(addrConnect, conn, proxyConnectionFailed);
if (!connected) {
LOCK(m_unused_i2p_sessions_mutex);
if (m_unused_i2p_sessions.size() < MAX_UNUSED_I2P_SESSIONS_SIZE) {
m_unused_i2p_sessions.emplace(i2p_transient_session.release());
}
}
}

if (connected) {
Expand Down Expand Up @@ -1048,6 +1064,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,

bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
std::optional<int> max_connections;
switch (conn_type) {
case ConnectionType::INBOUND:
Expand Down Expand Up @@ -1510,6 +1527,7 @@ void CConnman::DumpAddresses()

void CConnman::ProcessAddrFetch()
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
std::string strDest;
{
LOCK(m_addr_fetches_mutex);
Expand Down Expand Up @@ -1578,6 +1596,7 @@ int CConnman::GetExtraBlockRelayCount() const

void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
FastRandomContext rng;
// Connect to specific addresses
Expand Down Expand Up @@ -1929,6 +1948,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const

void CConnman::ThreadOpenAddedConnections()
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_ADD_CONNECTION);
while (true)
{
Expand Down Expand Up @@ -1958,6 +1978,7 @@ void CConnman::ThreadOpenAddedConnections()
// if successful, this moves the passed grant to the constructed node
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, ConnectionType conn_type)
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);

//
Expand Down
33 changes: 27 additions & 6 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <map>
#include <memory>
#include <optional>
#include <queue>
#include <thread>
#include <vector>

Expand Down Expand Up @@ -744,7 +745,7 @@ class CConnman
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
void SetNetworkActive(bool active);
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type);
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
bool CheckIncomingNonce(uint64_t nonce);

bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
Expand Down Expand Up @@ -820,7 +821,7 @@ class CConnman
* - Max total outbound connection capacity filled
* - Max connection capacity for type is filled
*/
bool AddConnection(const std::string& address, ConnectionType conn_type);
bool AddConnection(const std::string& address, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);

size_t GetNodeCount(ConnectionDirection) const;
void GetNodeStats(std::vector<CNodeStats>& vstats) const;
Expand Down Expand Up @@ -886,10 +887,10 @@ class CConnman
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const Options& options);

void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex);
void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex);
void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex);
void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex);
void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
void ThreadI2PAcceptIncoming();
void AcceptConnection(const ListenSocket& hListenSocket);
Expand Down Expand Up @@ -956,7 +957,7 @@ class CConnman
bool AlreadyConnectedToAddress(const CAddress& addr);

bool AttemptToEvictConnection();
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;

void DeleteNode(CNode* pnode);
Expand Down Expand Up @@ -1127,6 +1128,26 @@ class CConnman
*/
std::vector<CService> m_onion_binds;

/**
* Mutex protecting m_i2p_sam_sessions.
*/
Mutex m_unused_i2p_sessions_mutex;

/**
* A pool of created I2P SAM transient sessions that should be used instead
* of creating new ones in order to reduce the load on the I2P network.
* Creating a session in I2P is not cheap, thus if this is not empty, then
* pick an entry from it instead of creating a new session. If connecting to
* a host fails, then the created session is put to this pool for reuse.
*/
std::queue<std::unique_ptr<i2p::sam::Session>> m_unused_i2p_sessions GUARDED_BY(m_unused_i2p_sessions_mutex);

/**
* Cap on the size of `m_unused_i2p_sessions`, to ensure it does not
* unexpectedly use too much memory.
*/
static constexpr size_t MAX_UNUSED_I2P_SESSIONS_SIZE{10};

/**
* RAII helper to atomically create a copy of `m_nodes` and add a reference
* to each of the nodes. The nodes are released when this object is destroyed.
Expand Down
15 changes: 14 additions & 1 deletion src/qt/overviewpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ void OverviewPage::setWalletModel(WalletModel *model)
// Set up transaction list
filter.reset(new TransactionFilterProxy());
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
Expand All @@ -273,6 +272,10 @@ void OverviewPage::setWalletModel(WalletModel *model)
ui->listTransactions->setModel(filter.get());
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

connect(filter.get(), &TransactionFilterProxy::rowsInserted, this, &OverviewPage::LimitTransactionRows);
connect(filter.get(), &TransactionFilterProxy::rowsRemoved, this, &OverviewPage::LimitTransactionRows);
connect(filter.get(), &TransactionFilterProxy::rowsMoved, this, &OverviewPage::LimitTransactionRows);
LimitTransactionRows();
// Keep up to date with wallet
setBalance(model->getCachedBalance());
connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance);
Expand Down Expand Up @@ -301,6 +304,16 @@ void OverviewPage::changeEvent(QEvent* e)
QWidget::changeEvent(e);
}

// Only show most recent NUM_ITEMS rows
void OverviewPage::LimitTransactionRows()
{
if (filter && ui->listTransactions && ui->listTransactions->model() && filter.get() == ui->listTransactions->model()) {
for (int i = 0; i < filter->rowCount(); ++i) {
ui->listTransactions->setRowHidden(i, i >= NUM_ITEMS);
}
}
}

void OverviewPage::updateDisplayUnit()
{
if (walletModel && walletModel->getOptionsModel()) {
Expand Down
1 change: 1 addition & 0 deletions src/qt/overviewpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public Q_SLOTS:
std::unique_ptr<TransactionFilterProxy> filter;

private Q_SLOTS:
void LimitTransactionRows();
void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings);
Expand Down
18 changes: 0 additions & 18 deletions src/qt/transactionfilterproxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
typeFilter(ALL_TYPES),
watchOnlyFilter(WatchOnlyFilter_All),
minAmount(0),
limitRows(-1),
showInactive(true)
{
}
Expand Down Expand Up @@ -92,25 +91,8 @@ void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter)
invalidateFilter();
}

void TransactionFilterProxy::setLimit(int limit)
{
this->limitRows = limit;
}

void TransactionFilterProxy::setShowInactive(bool _showInactive)
{
this->showInactive = _showInactive;
invalidateFilter();
}

int TransactionFilterProxy::rowCount(const QModelIndex &parent) const
{
if(limitRows != -1)
{
return std::min(QSortFilterProxyModel::rowCount(parent), limitRows);
}
else
{
return QSortFilterProxyModel::rowCount(parent);
}
}
6 changes: 0 additions & 6 deletions src/qt/transactionfilterproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,9 @@ class TransactionFilterProxy : public QSortFilterProxyModel
void setMinAmount(const CAmount& minimum);
void setWatchOnlyFilter(WatchOnlyFilter filter);

/** Set maximum number of rows returned, -1 if unlimited. */
void setLimit(int limit);

/** Set whether to show conflicted transactions. */
void setShowInactive(bool showInactive);

int rowCount(const QModelIndex &parent = QModelIndex()) const override;

protected:
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;

Expand All @@ -60,7 +55,6 @@ class TransactionFilterProxy : public QSortFilterProxyModel
quint32 typeFilter;
WatchOnlyFilter watchOnlyFilter;
CAmount minAmount;
int limitRows;
bool showInactive;
};

Expand Down
3 changes: 3 additions & 0 deletions src/support/lockedpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#endif

#include <algorithm>
#include <limits>
#include <stdexcept>
#include <utility>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
Expand Down
4 changes: 2 additions & 2 deletions src/support/lockedpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#ifndef BITCOIN_SUPPORT_LOCKEDPOOL_H
#define BITCOIN_SUPPORT_LOCKEDPOOL_H

#include <stdint.h>
#include <cstddef>
#include <list>
#include <map>
#include <mutex>
#include <memory>
#include <mutex>
#include <unordered_map>

/**
Expand Down
14 changes: 14 additions & 0 deletions src/test/streams_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,18 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
fs::remove(streams_test_filename);
}

BOOST_AUTO_TEST_CASE(streams_hashed)
{
CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
HashedSourceWriter hash_writer{stream};
const std::string data{"bitcoin"};
hash_writer << data;

CHashVerifier hash_verifier{&stream};
std::string result;
hash_verifier >> result;
BOOST_CHECK_EQUAL(data, result);
BOOST_CHECK_EQUAL(hash_writer.GetHash(), hash_verifier.GetHash());
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit c8c85ca

Please sign in to comment.