Skip to content

feat: introduce type-flexible NetInfoEntry to allow non-CService entries, use in MnNetInfo #6629

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 27 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3814a0f
refactor: store `tx_hash` instead of calling `GetHash()` repeatedly
kwvg Mar 23, 2025
2bbe1b6
refactor: implement string padding and replace some ostringstream usage
kwvg Mar 23, 2025
35016f5
chore: use ProTx hash to identify masternodes in logs when possible
kwvg Mar 22, 2025
72beb58
refactor: defer resolving masternode service in CoinJoin code
kwvg Mar 28, 2025
51fcd26
refactor: cleanup index code, style updates, deduplication
kwvg Mar 29, 2025
c828e63
refactor: use `UniValue::VOBJ` instead of `setObject()` when possible
kwvg Mar 29, 2025
f9791d3
refactor: consolidate ProTx versioning, make logic friendly to upgrades
kwvg Mar 30, 2025
d4ebe69
refactor: rename CPro*Tx::GetVersion() to GetMaxVersion(), increase use
kwvg Apr 6, 2025
d8ede5a
refactor: rearrange checks in ProTx RPC wrapper to bail out faster
kwvg Apr 4, 2025
8b5aab3
refactor: replace `CDeterministicMNStateDiff` macros with `boost::hana`
kwvg Apr 7, 2025
3857579
fix: avoid potential "no user-provided default constructor" error
kwvg Apr 7, 2025
2a46f82
refactor: section off masternode service to `MnNetInfo`
kwvg Apr 10, 2025
aa1d394
refactor: use const-ref when accessing `MnNetInfo::addr` if read-only
kwvg Apr 4, 2025
81e9862
refactor: remove direct access to `MnNetInfo::addr`
kwvg Mar 28, 2025
59f647c
refactor: move address lookup to `MnNetInfo::AddEntry()`
kwvg Apr 8, 2025
a1467f3
fix: correct `simplifiedmns_merkleroots` unit test
kwvg Feb 3, 2025
8b88255
refactor: move service validation to `MnNetInfo`, run during setting
kwvg Apr 8, 2025
1ad4edc
refactor: implement `MnNetInfo::ToString()` for printing internal state
kwvg Mar 29, 2025
b94ad40
refactor: impl `GetEntries()`, adapt to support multiple addresses
kwvg Apr 10, 2025
807de7f
refactor: track every `MnNetInfo` entry in the unique property map
kwvg Apr 7, 2025
a92ec4f
evo: introduce type-flexible `NetInfoEntry` to allow non-`CService` data
kwvg Apr 11, 2025
a59d8f4
evo: change internal type of `MnNetInfo` to `NetInfoEntry`
kwvg Apr 11, 2025
c55dea9
evo: return `MnNetInfo::GetEntries()` with `NetInfoEntry`
kwvg Apr 10, 2025
53ed8d0
evo: utilize `NetInfoEntry::IsTriviallyValid()` in ProTx trivial checks
kwvg Apr 8, 2025
7553cfc
evo: allow swapping `MnNetInfo` with a differing underlying impl
kwvg Apr 11, 2025
3e08309
evo: prohibit overwriting entry in `MnNetInfo`
kwvg Apr 9, 2025
e8caf7e
evo: fast-fail `MnNetInfo::AddEntry()` if invalid characters found
kwvg Apr 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ BITCOIN_CORE_H = \
evo/evodb.h \
evo/mnauth.h \
evo/mnhftx.h \
evo/netinfo.h \
evo/providertx.h \
evo/simplifiedmns.h \
evo/specialtx.h \
Expand Down Expand Up @@ -773,6 +774,7 @@ libbitcoin_common_a_SOURCES = \
core_read.cpp \
core_write.cpp \
deploymentinfo.cpp \
evo/netinfo.cpp \
governance/common.cpp \
init/common.cpp \
key.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ BITCOIN_TESTS =\
test/evo_deterministicmns_tests.cpp \
test/evo_islock_tests.cpp \
test/evo_mnhf_tests.cpp \
test/evo_netinfo_tests.cpp \
test/evo_simplifiedmns_tests.cpp \
test/evo_trivialvalidation.cpp \
test/evo_utils_tests.cpp \
Expand Down
90 changes: 39 additions & 51 deletions src/coinjoin/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,9 @@ PeerMsgRet CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CConnm
// if the queue is ready, submit if we can
if (dsq.fReady &&
m_walletman.ForAnyCJClientMan([this, &connman, &dmn](std::unique_ptr<CCoinJoinClientManager>& clientman) {
return clientman->TrySubmitDenominate(dmn->pdmnState->addr, connman);
return clientman->TrySubmitDenominate(dmn->proTxHash, connman);
})) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue (%s) is ready on masternode %s\n", dsq.ToString(),
dmn->pdmnState->addr.ToStringAddrPort());
LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue is ready, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());
return {};
} else {
int64_t nLastDsq = m_mn_metaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
Expand All @@ -125,8 +124,7 @@ PeerMsgRet CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CConnm

m_mn_metaman.AllowMixing(dmn->proTxHash);

LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue (%s) from masternode %s\n", dsq.ToString(),
dmn->pdmnState->addr.ToStringAddrPort());
LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());

m_walletman.ForAnyCJClientMan([&dsq](const std::unique_ptr<CCoinJoinClientManager>& clientman) {
return clientman->MarkAlreadyJoinedQueueAsTried(dsq);
Expand Down Expand Up @@ -186,23 +184,15 @@ void CCoinJoinClientSession::ProcessMessage(CNode& peer, CChainState& active_cha
if (!CCoinJoinClientOptions::IsEnabled()) return;
if (!m_mn_sync.IsBlockchainSynced()) return;

if (msg_type == NetMsgType::DSSTATUSUPDATE) {
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->addr != peer.addr) {
return;
}
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->netInfo->GetPrimary() != peer.addr) return;

if (msg_type == NetMsgType::DSSTATUSUPDATE) {
CCoinJoinStatusUpdate psssup;
vRecv >> psssup;

ProcessPoolStateUpdate(psssup);

} else if (msg_type == NetMsgType::DSFINALTX) {
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->addr != peer.addr) {
return;
}

int nMsgSessionID;
vRecv >> nMsgSessionID;
CTransaction txNew(deserialize, vRecv);
Expand All @@ -216,15 +206,7 @@ void CCoinJoinClientSession::ProcessMessage(CNode& peer, CChainState& active_cha

// check to see if input is spent already? (and probably not confirmed)
SignFinalTransaction(peer, active_chainstate, connman, mempool, txNew);

} else if (msg_type == NetMsgType::DSCOMPLETE) {
if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->addr != peer.addr) {
WalletCJLogPrint(m_wallet, "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n",
mixingMasternode->pdmnState->addr.ToStringAddrPort(), peer.addr.ToStringAddrPort());
return;
}

int nMsgSessionID;
PoolMessage nMsgMessageID;
vRecv >> nMsgSessionID >> nMsgMessageID;
Expand Down Expand Up @@ -1124,24 +1106,21 @@ bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized,

m_clientman.AddUsedMasternode(dsq.masternodeOutpoint);

if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) {
if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo->GetPrimary())) {
WalletCJLogPrint(m_wallet, /* Continued */
"CCoinJoinClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n",
dmn->pdmnState->addr.ToStringAddrPort());
"CCoinJoinClientSession::JoinExistingQueue -- skipping connection, masternode=%s\n", dmn->proTxHash.ToString());
continue;
}

nSessionDenom = dsq.nDenom;
mixingMasternode = dmn;
pendingDsaRequest = CPendingDsaRequest(dmn->pdmnState->addr, CCoinJoinAccept(nSessionDenom, txMyCollateral));
pendingDsaRequest = CPendingDsaRequest(dmn->proTxHash, CCoinJoinAccept(nSessionDenom, txMyCollateral));
connman.AddPendingMasternode(dmn->proTxHash);
SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTime();
WalletCJLogPrint(m_wallet, /* Continued */
"CCoinJoinClientSession::JoinExistingQueue -- pending connection (from queue): nSessionDenom: "
"%d (%s), addr=%s\n",
nSessionDenom, CoinJoin::DenominationToString(nSessionDenom),
dmn->pdmnState->addr.ToStringAddrPort());
"CCoinJoinClientSession::JoinExistingQueue -- pending connection, masternode=%s, nSessionDenom=%d (%s)\n",
dmn->proTxHash.ToString(), nSessionDenom, CoinJoin::DenominationToString(nSessionDenom));
strAutoDenomResult = _("Trying to connect…");
return true;
}
Expand Down Expand Up @@ -1192,23 +1171,22 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon
int64_t nDsqThreshold = m_mn_metaman.GetDsqThreshold(dmn->proTxHash, nMnCount);
if (nLastDsq != 0 && nDsqThreshold > m_mn_metaman.GetDsqCount()) {
WalletCJLogPrint(m_wallet, /* Continued */
"CCoinJoinClientSession::StartNewQueue -- Too early to mix on this masternode!" /* Continued */
" masternode=%s addr=%s nLastDsq=%d nDsqThreshold=%d nDsqCount=%d\n",
dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToStringAddrPort(), nLastDsq,
nDsqThreshold, m_mn_metaman.GetDsqCount());
"CCoinJoinClientSession::StartNewQueue -- too early to mix with node," /* Continued */
" masternode=%s, nLastDsq=%d, nDsqThreshold=%d, nDsqCount=%d\n",
dmn->proTxHash.ToString(), nLastDsq, nDsqThreshold, m_mn_metaman.GetDsqCount());
nTries++;
continue;
}

if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- skipping masternode connection, addr=%s\n",
dmn->pdmnState->addr.ToStringAddrPort());
if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo->GetPrimary())) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- skipping connection, masternode=%s\n",
dmn->proTxHash.ToString());
nTries++;
continue;
}

WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- attempt %d connection to Masternode %s\n",
nTries, dmn->pdmnState->addr.ToStringAddrPort());
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- attempting connection, masternode=%s, tries=%s\n",
dmn->proTxHash.ToString(), nTries);

// try to get a single random denom out of setAmounts
while (nSessionDenom == 0) {
Expand All @@ -1221,12 +1199,12 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon

mixingMasternode = dmn;
connman.AddPendingMasternode(dmn->proTxHash);
pendingDsaRequest = CPendingDsaRequest(dmn->pdmnState->addr, CCoinJoinAccept(nSessionDenom, txMyCollateral));
pendingDsaRequest = CPendingDsaRequest(dmn->proTxHash, CCoinJoinAccept(nSessionDenom, txMyCollateral));
SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTime();
WalletCJLogPrint( /* Continued */
m_wallet, "CCoinJoinClientSession::StartNewQueue -- pending connection, nSessionDenom: %d (%s), addr=%s\n",
nSessionDenom, CoinJoin::DenominationToString(nSessionDenom), dmn->pdmnState->addr.ToStringAddrPort());
m_wallet, "CCoinJoinClientSession::StartNewQueue -- pending connection, masternode=%s, nSessionDenom=%d (%s)\n",
dmn->proTxHash.ToString(), nSessionDenom, CoinJoin::DenominationToString(nSessionDenom));
strAutoDenomResult = _("Trying to connect…");
return true;
}
Expand All @@ -1238,7 +1216,17 @@ bool CCoinJoinClientSession::ProcessPendingDsaRequest(CConnman& connman)
{
if (!pendingDsaRequest) return false;

bool fDone = connman.ForNode(pendingDsaRequest.GetAddr(), [this, &connman](CNode* pnode) {
CService mn_addr;
if (auto dmn = m_dmnman.GetListAtChainTip().GetMN(pendingDsaRequest.GetProTxHash())) {
mn_addr = Assert(dmn->pdmnState)->netInfo->GetPrimary();
} else {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- cannot find address to connect, masternode=%s\n", __func__,
pendingDsaRequest.GetProTxHash().ToString());
WITH_LOCK(cs_coinjoin, SetNull());
return false;
}

bool fDone = connman.ForNode(mn_addr, [this, &connman](CNode* pnode) {
WalletCJLogPrint(m_wallet, "-- processing dsa queue for addr=%s\n", pnode->addr.ToStringAddrPort());
nTimeLastSuccessfulStep = GetTime();
CNetMsgMaker msgMaker(pnode->GetCommonVersion());
Expand All @@ -1249,8 +1237,8 @@ bool CCoinJoinClientSession::ProcessPendingDsaRequest(CConnman& connman)
if (fDone) {
pendingDsaRequest = CPendingDsaRequest();
} else if (pendingDsaRequest.IsExpired()) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- failed to connect to %s\n", __func__,
pendingDsaRequest.GetAddr().ToStringAddrPort());
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- failed to connect, masternode=%s\n", __func__,
pendingDsaRequest.GetProTxHash().ToString());
WITH_LOCK(cs_coinjoin, SetNull());
}

Expand All @@ -1268,13 +1256,13 @@ void CCoinJoinClientManager::ProcessPendingDsaRequest(CConnman& connman)
}
}

bool CCoinJoinClientManager::TrySubmitDenominate(const CService& mnAddr, CConnman& connman)
bool CCoinJoinClientManager::TrySubmitDenominate(const uint256& proTxHash, CConnman& connman)
{
AssertLockNotHeld(cs_deqsessions);
LOCK(cs_deqsessions);
for (auto& session : deqSessions) {
CDeterministicMNCPtr mnMixing;
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->pdmnState->addr == mnAddr && session.GetState() == POOL_STATE_QUEUE) {
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->proTxHash == proTxHash && session.GetState() == POOL_STATE_QUEUE) {
session.SubmitDenominate(connman);
return true;
}
Expand Down Expand Up @@ -1832,7 +1820,7 @@ void CCoinJoinClientSession::RelayIn(const CCoinJoinEntry& entry, CConnman& conn
{
if (!mixingMasternode) return;

connman.ForNode(mixingMasternode->pdmnState->addr, [&entry, &connman, this](CNode* pnode) {
connman.ForNode(mixingMasternode->pdmnState->netInfo->GetPrimary(), [&entry, &connman, this](CNode* pnode) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::RelayIn -- found master, relaying message to %s\n",
pnode->addr.ToStringAddrPort());
CNetMsgMaker msgMaker(pnode->GetCommonVersion());
Expand Down Expand Up @@ -1888,7 +1876,7 @@ void CCoinJoinClientSession::GetJsonInfo(UniValue& obj) const
assert(mixingMasternode->pdmnState);
obj.pushKV("protxhash", mixingMasternode->proTxHash.ToString());
obj.pushKV("outpoint", mixingMasternode->collateralOutpoint.ToStringShort());
obj.pushKV("service", mixingMasternode->pdmnState->addr.ToStringAddrPort());
obj.pushKV("service", mixingMasternode->pdmnState->netInfo->GetPrimary().ToStringAddrPort());
}
obj.pushKV("denomination", ValueFromAmount(CoinJoin::DenominationToAmount(nSessionDenom)));
obj.pushKV("state", GetStateString());
Expand Down
12 changes: 6 additions & 6 deletions src/coinjoin/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,27 @@ class CPendingDsaRequest
private:
static constexpr int TIMEOUT = 15;

CService addr;
uint256 proTxHash;
CCoinJoinAccept dsa;
int64_t nTimeCreated{0};

public:
CPendingDsaRequest() = default;

CPendingDsaRequest(CService addr_, CCoinJoinAccept dsa_) :
addr(std::move(addr_)),
CPendingDsaRequest(uint256 proTxHash_, CCoinJoinAccept dsa_) :
proTxHash(std::move(proTxHash_)),
dsa(std::move(dsa_)),
nTimeCreated(GetTime())
{
}

[[nodiscard]] CService GetAddr() const { return addr; }
[[nodiscard]] uint256 GetProTxHash() const { return proTxHash; }
[[nodiscard]] CCoinJoinAccept GetDSA() const { return dsa; }
[[nodiscard]] bool IsExpired() const { return GetTime() - nTimeCreated > TIMEOUT; }

friend bool operator==(const CPendingDsaRequest& a, const CPendingDsaRequest& b)
{
return a.addr == b.addr && a.dsa == b.dsa;
return a.proTxHash == b.proTxHash && a.dsa == b.dsa;
}
friend bool operator!=(const CPendingDsaRequest& a, const CPendingDsaRequest& b)
{
Expand Down Expand Up @@ -336,7 +336,7 @@ class CCoinJoinClientManager
bool DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool,
bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);

bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
bool TrySubmitDenominate(const uint256& proTxHash, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);

void CheckTimeout() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
Expand Down
6 changes: 2 additions & 4 deletions src/coinjoin/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,12 @@ PeerMsgRet CCoinJoinServer::ProcessDSQUEUE(const CNode& peer, CDataStream& vRecv
LogPrint(BCLog::COINJOIN, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, nDsqThreshold, m_mn_metaman.GetDsqCount());
//don't allow a few nodes to dominate the queuing process
if (nLastDsq != 0 && nDsqThreshold > m_mn_metaman.GetDsqCount()) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n",
dmn->pdmnState->addr.ToStringAddrPort());
LogPrint(BCLog::COINJOIN, "DSQUEUE -- node sending too many dsq messages, masternode=%s\n", dmn->proTxHash.ToString());
return {};
}
m_mn_metaman.AllowMixing(dmn->proTxHash);

LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue (%s) from masternode %s\n", dsq.ToString(),
dmn->pdmnState->addr.ToStringAddrPort());
LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());

TRY_LOCK(cs_vecqueue, lockRecv);
if (!lockRecv) return {};
Expand Down
3 changes: 1 addition & 2 deletions src/evo/assetlocktx.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ class CAssetUnlockPayload

[[nodiscard]] UniValue ToJson() const
{
UniValue obj;
obj.setObject();
UniValue obj(UniValue::VOBJ);
obj.pushKV("version", int(nVersion));
obj.pushKV("index", int(index));
obj.pushKV("fee", int(fee));
Expand Down
3 changes: 1 addition & 2 deletions src/evo/cbtx.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ class CCbTx

[[nodiscard]] UniValue ToJson() const
{
UniValue obj;
obj.setObject();
UniValue obj(UniValue::VOBJ);
obj.pushKV("version", (int)nVersion);
obj.pushKV("height", nHeight);
obj.pushKV("merkleRootMNList", merkleRootMNList.ToString());
Expand Down
Loading
Loading