dash/src/coinjoin/coinjoin.cpp

620 lines
19 KiB
C++
Raw Normal View History

// Copyright (c) 2014-2021 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2018-11-05 10:29:33 +01:00
#include <coinjoin/coinjoin.h>
#include <core_io.h>
Backport 11651 (#3358) * scripted-diff: Replace #include "" with #include <> (ryanofsky) -BEGIN VERIFY SCRIPT- for f in \ src/*.cpp \ src/*.h \ src/bench/*.cpp \ src/bench/*.h \ src/compat/*.cpp \ src/compat/*.h \ src/consensus/*.cpp \ src/consensus/*.h \ src/crypto/*.cpp \ src/crypto/*.h \ src/crypto/ctaes/*.h \ src/policy/*.cpp \ src/policy/*.h \ src/primitives/*.cpp \ src/primitives/*.h \ src/qt/*.cpp \ src/qt/*.h \ src/qt/test/*.cpp \ src/qt/test/*.h \ src/rpc/*.cpp \ src/rpc/*.h \ src/script/*.cpp \ src/script/*.h \ src/support/*.cpp \ src/support/*.h \ src/support/allocators/*.h \ src/test/*.cpp \ src/test/*.h \ src/wallet/*.cpp \ src/wallet/*.h \ src/wallet/test/*.cpp \ src/wallet/test/*.h \ src/zmq/*.cpp \ src/zmq/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * scripted-diff: Replace #include "" with #include <> (Dash Specific) -BEGIN VERIFY SCRIPT- for f in \ src/bls/*.cpp \ src/bls/*.h \ src/evo/*.cpp \ src/evo/*.h \ src/governance/*.cpp \ src/governance/*.h \ src/llmq/*.cpp \ src/llmq/*.h \ src/masternode/*.cpp \ src/masternode/*.h \ src/privatesend/*.cpp \ src/privatesend/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * build: Remove -I for everything but project root Remove -I from build system for everything but the project root, and built-in dependencies. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/Makefile.test.include * qt: refactor: Use absolute include paths in .ui files * qt: refactor: Changes to make include paths absolute This makes all include paths in the GUI absolute. Many changes are involved as every single source file in src/qt/ assumes to be able to use relative includes. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/qt/dash.cpp # src/qt/optionsmodel.cpp # src/qt/test/rpcnestedtests.cpp * test: refactor: Use absolute include paths for test data files * Recommend #include<> syntax in developer notes * refactor: Include obj/build.h instead of build.h * END BACKPORT #11651 Remove trailing whitespace causing travis failure * fix backport 11651 Signed-off-by: Pasta <pasta@dashboost.org> * More of 11651 * fix blockchain.cpp Signed-off-by: pasta <pasta@dashboost.org> * Add missing "qt/" in includes * Add missing "test/" in includes * Fix trailing whitespaces Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: Russell Yanofsky <russ@yanofsky.org> Co-authored-by: MeshCollider <dobsonsa68@gmail.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
2020-03-19 23:46:56 +01:00
#include <consensus/validation.h>
#include <chain.h>
Backport 11651 (#3358) * scripted-diff: Replace #include "" with #include <> (ryanofsky) -BEGIN VERIFY SCRIPT- for f in \ src/*.cpp \ src/*.h \ src/bench/*.cpp \ src/bench/*.h \ src/compat/*.cpp \ src/compat/*.h \ src/consensus/*.cpp \ src/consensus/*.h \ src/crypto/*.cpp \ src/crypto/*.h \ src/crypto/ctaes/*.h \ src/policy/*.cpp \ src/policy/*.h \ src/primitives/*.cpp \ src/primitives/*.h \ src/qt/*.cpp \ src/qt/*.h \ src/qt/test/*.cpp \ src/qt/test/*.h \ src/rpc/*.cpp \ src/rpc/*.h \ src/script/*.cpp \ src/script/*.h \ src/support/*.cpp \ src/support/*.h \ src/support/allocators/*.h \ src/test/*.cpp \ src/test/*.h \ src/wallet/*.cpp \ src/wallet/*.h \ src/wallet/test/*.cpp \ src/wallet/test/*.h \ src/zmq/*.cpp \ src/zmq/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * scripted-diff: Replace #include "" with #include <> (Dash Specific) -BEGIN VERIFY SCRIPT- for f in \ src/bls/*.cpp \ src/bls/*.h \ src/evo/*.cpp \ src/evo/*.h \ src/governance/*.cpp \ src/governance/*.h \ src/llmq/*.cpp \ src/llmq/*.h \ src/masternode/*.cpp \ src/masternode/*.h \ src/privatesend/*.cpp \ src/privatesend/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * build: Remove -I for everything but project root Remove -I from build system for everything but the project root, and built-in dependencies. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/Makefile.test.include * qt: refactor: Use absolute include paths in .ui files * qt: refactor: Changes to make include paths absolute This makes all include paths in the GUI absolute. Many changes are involved as every single source file in src/qt/ assumes to be able to use relative includes. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/qt/dash.cpp # src/qt/optionsmodel.cpp # src/qt/test/rpcnestedtests.cpp * test: refactor: Use absolute include paths for test data files * Recommend #include<> syntax in developer notes * refactor: Include obj/build.h instead of build.h * END BACKPORT #11651 Remove trailing whitespace causing travis failure * fix backport 11651 Signed-off-by: Pasta <pasta@dashboost.org> * More of 11651 * fix blockchain.cpp Signed-off-by: pasta <pasta@dashboost.org> * Add missing "qt/" in includes * Add missing "test/" in includes * Fix trailing whitespaces Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: Russell Yanofsky <russ@yanofsky.org> Co-authored-by: MeshCollider <dobsonsa68@gmail.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
2020-03-19 23:46:56 +01:00
#include <messagesigner.h>
#include <netmessagemaker.h>
#include <script/sign.h>
#include <txmempool.h>
#include <util.h>
#include <utilmoneystr.h>
#include <validation.h>
#include <bls/bls.h>
#include <masternode/activemasternode.h>
#include <masternode/masternode-sync.h>
Backport 11651 (#3358) * scripted-diff: Replace #include "" with #include <> (ryanofsky) -BEGIN VERIFY SCRIPT- for f in \ src/*.cpp \ src/*.h \ src/bench/*.cpp \ src/bench/*.h \ src/compat/*.cpp \ src/compat/*.h \ src/consensus/*.cpp \ src/consensus/*.h \ src/crypto/*.cpp \ src/crypto/*.h \ src/crypto/ctaes/*.h \ src/policy/*.cpp \ src/policy/*.h \ src/primitives/*.cpp \ src/primitives/*.h \ src/qt/*.cpp \ src/qt/*.h \ src/qt/test/*.cpp \ src/qt/test/*.h \ src/rpc/*.cpp \ src/rpc/*.h \ src/script/*.cpp \ src/script/*.h \ src/support/*.cpp \ src/support/*.h \ src/support/allocators/*.h \ src/test/*.cpp \ src/test/*.h \ src/wallet/*.cpp \ src/wallet/*.h \ src/wallet/test/*.cpp \ src/wallet/test/*.h \ src/zmq/*.cpp \ src/zmq/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * scripted-diff: Replace #include "" with #include <> (Dash Specific) -BEGIN VERIFY SCRIPT- for f in \ src/bls/*.cpp \ src/bls/*.h \ src/evo/*.cpp \ src/evo/*.h \ src/governance/*.cpp \ src/governance/*.h \ src/llmq/*.cpp \ src/llmq/*.h \ src/masternode/*.cpp \ src/masternode/*.h \ src/privatesend/*.cpp \ src/privatesend/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * build: Remove -I for everything but project root Remove -I from build system for everything but the project root, and built-in dependencies. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/Makefile.test.include * qt: refactor: Use absolute include paths in .ui files * qt: refactor: Changes to make include paths absolute This makes all include paths in the GUI absolute. Many changes are involved as every single source file in src/qt/ assumes to be able to use relative includes. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/qt/dash.cpp # src/qt/optionsmodel.cpp # src/qt/test/rpcnestedtests.cpp * test: refactor: Use absolute include paths for test data files * Recommend #include<> syntax in developer notes * refactor: Include obj/build.h instead of build.h * END BACKPORT #11651 Remove trailing whitespace causing travis failure * fix backport 11651 Signed-off-by: Pasta <pasta@dashboost.org> * More of 11651 * fix blockchain.cpp Signed-off-by: pasta <pasta@dashboost.org> * Add missing "qt/" in includes * Add missing "test/" in includes * Fix trailing whitespaces Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: Russell Yanofsky <russ@yanofsky.org> Co-authored-by: MeshCollider <dobsonsa68@gmail.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
2020-03-19 23:46:56 +01:00
#include <llmq/quorums_instantsend.h>
#include <llmq/quorums_chainlocks.h>
#include <string>
bool CCoinJoinEntry::AddScriptSig(const CTxIn& txin)
{
for (auto& txdsin : vecTxDSIn) {
2018-11-05 10:29:07 +01:00
if (txdsin.prevout == txin.prevout && txdsin.nSequence == txin.nSequence) {
if (txdsin.fHasSig) return false;
txdsin.scriptSig = txin.scriptSig;
txdsin.fHasSig = true;
return true;
}
}
return false;
}
uint256 CCoinJoinQueue::GetSignatureHash() const
{
Remove all legacy/compatibility MN code (#2600) * Remove CActiveLegacyMasternodeManager * Remove sentinelping RPC * Remove unused P2P messages and inv types There are still places where these are used in the code. The next commits will clean these up. * Remove MNB/MNP/MNVERIFY related code from masternode(man).h/cpp * Remove all legacy code regarding block MN payee voting * Remove MASTERNODE_SYNC_LIST and MASTERNODE_SYNC_MNW states Also replace all uses of IsMasternodeListSynced and IsWinnersListSynced with IsBlockchainSynced. * Remove unsupported masternode RPCs * Remove UpdateLastPaid methods * Remove duplicate deterministicmns.h include * Remove masternode.conf support * Remove legacy MN lists support from masternode list GUI * Remove unnecessary AskForMN call * Remove compatibility code in CPrivateSendQueue::GetSignatureHash * Don't add locally calculated MN payee in case GetBlockTxOuts failed This is not valid in DIP3 mode * Remove check for IsDeterministicMNsSporkActive in "masternode status" * Move CMasternode::IsValidNetAddr to CActiveDeterministicMasternodeManager * Remove use of CMasternode::CheckCollateral in governance code * Remove uses of MASTERNODE_SENTINEL_PING_MAX_SECONDS/MASTERNODE_SENTINEL_PING_MAX_SECONDS * Remove support for "-masternodeprivkey" * Remove pre-DIP3 vote cleanup * Remove compatibility code for quorumModifierHash/masternodeProTxHash * Remove check for invalid nBlockHeight in CMasternodePayments::GetBlockTxOuts ...and let it crash instead. We expect this method to be called with the correct height now (after DIP3 was fully deployed). * Remove ECDSA based Sign/CheckSignature from CGovernanceObject Only masternodes sign governance objects, so there is no need for ECDSA support here anymore. * Always add superblock and MN reward payments into new block * Always check block payees (except if fLiteMode==true) * Always allow superblock and MN payees in same block * Remove/Fix a few references to masternode.conf and related stuff Also delete guide-startmany.md and masternode_conf.md * Implement NotifyMasternodeListChanged signal and call governance maintenance * Remove non-DIP3 code path from CMasternodeMan::Find * Remove remaining unused code from CMasternode/CMasternodeMan * Always load governance.dat on startup * Mine an empty block instead of incrementing nHeight from chain tip in miner tests This test is crashing otherwise in GetBlockTxOuts as it tries to access a previous block that is not existing. * Skip MN payments verification on historical blocks (pre-DIP3 blocks) Even though DIP3 was active on BIP9 level, the spork was not active yet at that point meaning that payments were not enforced at that time. * Remove unused state and CollateralStatus enums * Unconditionally return false from IsBlockPayeeValid when IsTransactionValid returns false IsTransactionValid already handles the case where IsDIP3Active() returns false, making it return true. * Add override keyword to CDSNotificationInterface::NotifyMasternodeListChanged * Fix help for masternodelist status (POSE_BANNED and no OUTPOINT_SPENT)
2019-01-03 10:17:43 +01:00
return SerializeHash(*this);
}
bool CCoinJoinQueue::Sign()
{
2018-11-05 10:29:07 +01:00
if (!fMasternodeMode) return false;
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
vchSig = sig.ToByteVector();
return true;
}
bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const
{
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash())) {
LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;
}
bool CCoinJoinQueue::Relay(CConnman& connman)
{
connman.ForEachNode([&connman, this](CNode* pnode) {
CNetMsgMaker msgMaker(pnode->GetSendVersion());
if (pnode->nVersion >= MIN_COINJOIN_PEER_PROTO_VERSION && pnode->fSendDSQueue) {
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSQUEUE, (*this)));
}
});
return true;
}
bool CCoinJoinQueue::IsTimeOutOfBounds() const
{
return GetAdjustedTime() - nTime > COINJOIN_QUEUE_TIMEOUT || nTime - GetAdjustedTime() > COINJOIN_QUEUE_TIMEOUT;
}
uint256 CCoinJoinBroadcastTx::GetSignatureHash() const
{
return SerializeHash(*this);
}
bool CCoinJoinBroadcastTx::Sign()
{
2018-11-05 10:29:07 +01:00
if (!fMasternodeMode) return false;
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
if (!sig.IsValid()) {
return false;
}
vchSig = sig.ToByteVector();
return true;
}
bool CCoinJoinBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const
{
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash())) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBroadcastTx::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;
}
bool CCoinJoinBroadcastTx::IsExpired(const CBlockIndex* pindex) const
{
// expire confirmed DSTXes after ~1h since confirmation or chainlocked confirmation
if (nConfirmedHeight == -1 || pindex->nHeight < nConfirmedHeight) return false; // not mined yet
if (pindex->nHeight - nConfirmedHeight > 24) return true; // mined more then an hour ago
return llmq::chainLocksHandler->HasChainLock(pindex->nHeight, *pindex->phashBlock);
}
refactor: misc refactoring in instantsend, llmq, coinjoin (#4212) * instantsend: make stuff const where possible Signed-off-by: pasta <pasta@dashboost.org> * instantsend: remove unused `params` Signed-off-by: pasta <pasta@dashboost.org> * instantsend: combine two nested if's into one Signed-off-by: pasta <pasta@dashboost.org> * instantsend: use auto in spots where possible and clear Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: make IsValidStructure const Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: divide by an integer to avoid double implicit conversions Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: make unused parameter unnamed Signed-off-by: pasta <pasta@dashboost.org> * quorums.* use const and use references where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums.h don't return const when returning by value Signed-off-by: pasta <pasta@dashboost.org> * quorums_blockprocessor.cpp remove redundant casts and combine two if statements Signed-off-by: pasta <pasta@dashboost.org> * quorums_blockprocessor.cpp make values const Signed-off-by: pasta <pasta@dashboost.org> * quorums_chainlocks.cpp access static function statically Signed-off-by: pasta <pasta@dashboost.org> * quorums_chainlocks.h remove commented out include Signed-off-by: pasta <pasta@dashboost.org> * quorums_commitment.cpp remove redundant casts Signed-off-by: pasta <pasta@dashboost.org> * quorums_debug.cpp remove redundant casts and add const Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsession.cpp use const where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp use const where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp don't use std::move which apparently prevents "copy elision" in this instance Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp use const Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionmgr.cpp misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_signing.* misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_signing_shares.* misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_utils.cpp misc refactoring Signed-off-by: pasta <pasta@dashboost.org>
2021-06-26 15:10:53 +02:00
bool CCoinJoinBroadcastTx::IsValidStructure() const
{
// some trivial checks only
if (tx->vin.size() != tx->vout.size()) {
return false;
}
if (tx->vin.size() < CCoinJoin::GetMinPoolParticipants()) {
return false;
}
if (tx->vin.size() > CCoinJoin::GetMaxPoolParticipants() * COINJOIN_ENTRY_MAX_SIZE) {
return false;
}
for (const auto& out : tx->vout) {
if (!CCoinJoin::IsDenominatedAmount(out.nValue)) {
return false;
}
if (!out.scriptPubKey.IsPayToPublicKeyHash()) {
return false;
}
}
return true;
}
void CCoinJoinBaseSession::SetNull()
{
// Both sides
LOCK(cs_coinjoin);
nState = POOL_STATE_IDLE;
nSessionID = 0;
nSessionDenom = 0;
vecEntries.clear();
finalMutableTransaction.vin.clear();
finalMutableTransaction.vout.clear();
nTimeLastSuccessfulStep = GetTime();
}
void CCoinJoinBaseManager::SetNull()
{
LOCK(cs_vecqueue);
vecCoinJoinQueue.clear();
}
void CCoinJoinBaseManager::CheckQueue()
{
TRY_LOCK(cs_vecqueue, lockDS);
2018-11-05 10:29:07 +01:00
if (!lockDS) return; // it's ok to fail here, we run this quite frequently
// check mixing queue objects for timeouts
auto it = vecCoinJoinQueue.begin();
while (it != vecCoinJoinQueue.end()) {
if ((*it).IsTimeOutOfBounds()) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseManager::%s -- Removing a queue (%s)\n", __func__, (*it).ToString());
it = vecCoinJoinQueue.erase(it);
} else {
2018-11-05 10:29:07 +01:00
++it;
}
}
}
bool CCoinJoinBaseManager::GetQueueItemAndTry(CCoinJoinQueue& dsqRet)
{
TRY_LOCK(cs_vecqueue, lockDS);
2018-11-05 10:29:07 +01:00
if (!lockDS) return false; // it's ok to fail here, we run this quite frequently
for (auto& dsq : vecCoinJoinQueue) {
// only try each queue once
if (dsq.fTried || dsq.IsTimeOutOfBounds()) continue;
dsq.fTried = true;
dsqRet = dsq;
return true;
}
return false;
}
std::string CCoinJoinBaseSession::GetStateString() const
{
2018-11-05 10:29:07 +01:00
switch (nState) {
case POOL_STATE_IDLE:
return "IDLE";
case POOL_STATE_QUEUE:
return "QUEUE";
case POOL_STATE_ACCEPTING_ENTRIES:
return "ACCEPTING_ENTRIES";
case POOL_STATE_SIGNING:
return "SIGNING";
case POOL_STATE_ERROR:
return "ERROR";
default:
return "UNKNOWN";
}
}
bool CCoinJoinBaseSession::IsValidInOuts(const std::vector<CTxIn>& vin, const std::vector<CTxOut>& vout, PoolMessage& nMessageIDRet, bool* fConsumeCollateralRet) const
{
std::set<CScript> setScripPubKeys;
nMessageIDRet = MSG_NOERR;
if (fConsumeCollateralRet) *fConsumeCollateralRet = false;
if (vin.size() != vout.size()) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::%s -- ERROR: inputs vs outputs size mismatch! %d vs %d\n", __func__, vin.size(), vout.size());
nMessageIDRet = ERR_SIZE_MISMATCH;
if (fConsumeCollateralRet) *fConsumeCollateralRet = true;
return false;
}
auto checkTxOut = [&](const CTxOut& txout) {
int nDenom = CCoinJoin::AmountToDenomination(txout.nValue);
if (nDenom != nSessionDenom) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::IsValidInOuts -- ERROR: incompatible denom %d (%s) != nSessionDenom %d (%s)\n",
nDenom, CCoinJoin::DenominationToString(nDenom), nSessionDenom, CCoinJoin::DenominationToString(nSessionDenom));
nMessageIDRet = ERR_DENOM;
if (fConsumeCollateralRet) *fConsumeCollateralRet = true;
return false;
}
if (!txout.scriptPubKey.IsPayToPublicKeyHash()) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::IsValidInOuts -- ERROR: invalid script! scriptPubKey=%s\n", ScriptToAsmStr(txout.scriptPubKey));
nMessageIDRet = ERR_INVALID_SCRIPT;
if (fConsumeCollateralRet) *fConsumeCollateralRet = true;
return false;
}
if (!setScripPubKeys.insert(txout.scriptPubKey).second) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::IsValidInOuts -- ERROR: already have this script! scriptPubKey=%s\n", ScriptToAsmStr(txout.scriptPubKey));
nMessageIDRet = ERR_ALREADY_HAVE;
if (fConsumeCollateralRet) *fConsumeCollateralRet = true;
return false;
}
// IsPayToPublicKeyHash() above already checks for scriptPubKey size,
// no need to double check, hence no usage of ERR_NON_STANDARD_PUBKEY
return true;
};
CAmount nFees{0};
for (const auto& txout : vout) {
if (!checkTxOut(txout)) {
return false;
}
nFees -= txout.nValue;
}
Merge #11043: Use std::unique_ptr (C++11) where possible a357293 Use MakeUnique<Db>(...) (practicalswift) 3e09b39 Use MakeUnique<T>(...) instead of std::unique_ptr<T>(new T(...)) (practicalswift) 8617989 Add MakeUnique (substitute for C++14 std::make_unique) (practicalswift) d223bc9 Use unique_ptr for pcoinscatcher/pcoinsdbview/pcoinsTip/pblocktree (practicalswift) b45c597 Use unique_ptr for pdbCopy (Db) and fix potential memory leak (practicalswift) 29ab96d Use unique_ptr for dbenv (DbEnv) (practicalswift) f72cbf9 Use unique_ptr for pfilter (CBloomFilter) (practicalswift) 8ccf1bb Use unique_ptr for sem{Addnode,Outbound} (CSemaphore) (practicalswift) 73db063 Use unique_ptr for upnp_thread (boost::thread) (practicalswift) 0024531 Use unique_ptr for dbw (CDBWrapper) (practicalswift) fa6d122 Use unique_ptr:s for {fee,short,long}Stats (TxConfirmStats) (practicalswift) 5a6f768 Use unique_ptr for httpRPCTimerInterface (HTTPRPCTimerInterface) (practicalswift) 860e912 Use unique_ptr for pwalletMain (CWallet) (practicalswift) Pull request description: Use `std::unique_ptr` (C++11) where possible. Rationale: 1. Avoid resource leaks (specifically: forgetting to `delete` an object created using `new`) 2. Avoid undefined behaviour (specifically: double `delete`:s) **Note to reviewers:** Please let me know if I've missed any obvious `std::unique_ptr` candidates. Hopefully this PR should cover all the trivial cases. Tree-SHA512: 9fbeb47b800ab8ff4e0be9f2a22ab63c23d5c613a0c6716d9183db8d22ddbbce592fb8384a8b7874bf7375c8161efb13ca2197ad6f24b75967148037f0f7b20c
2017-11-09 21:22:08 +01:00
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool);
for (const auto& txin : vin) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::%s -- txin=%s\n", __func__, txin.ToString());
if (txin.prevout.IsNull()) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::%s -- ERROR: invalid input!\n", __func__);
nMessageIDRet = ERR_INVALID_INPUT;
if (fConsumeCollateralRet) *fConsumeCollateralRet = true;
return false;
}
Coin coin;
if (!viewMemPool.GetCoin(txin.prevout, coin) || coin.IsSpent() ||
(coin.nHeight == MEMPOOL_HEIGHT && !llmq::quorumInstantSendManager->IsLocked(txin.prevout.hash))) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::%s -- ERROR: missing, spent or non-locked mempool input! txin=%s\n", __func__, txin.ToString());
nMessageIDRet = ERR_MISSING_TX;
return false;
}
if (!checkTxOut(coin.out)) {
return false;
}
nFees += coin.out.nValue;
}
// The same size and denom for inputs and outputs ensures their total value is also the same,
// no need to double check. If not, we are doing something wrong, bail out.
if (nFees != 0) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::%s -- ERROR: non-zero fees! fees: %lld\n", __func__, nFees);
nMessageIDRet = ERR_FEES;
return false;
}
return true;
}
// Definitions for static data members
std::vector<CAmount> CCoinJoin::vecStandardDenominations;
std::map<uint256, CCoinJoinBroadcastTx> CCoinJoin::mapDSTX;
CCriticalSection CCoinJoin::cs_mapdstx;
void CCoinJoin::InitStandardDenominations()
{
vecStandardDenominations.clear();
/* Denominations
A note about convertibility. Within mixing pools, each denomination
is convertible to another.
For example:
1DRK+1000 == (.1DRK+100)*10
10DRK+10000 == (1DRK+1000)*10
*/
/* Disabled
vecStandardDenominations.push_back( (100 * COIN)+100000 );
*/
2018-11-05 10:29:07 +01:00
vecStandardDenominations.push_back((10 * COIN) + 10000);
vecStandardDenominations.push_back((1 * COIN) + 1000);
refactor: misc refactoring in instantsend, llmq, coinjoin (#4212) * instantsend: make stuff const where possible Signed-off-by: pasta <pasta@dashboost.org> * instantsend: remove unused `params` Signed-off-by: pasta <pasta@dashboost.org> * instantsend: combine two nested if's into one Signed-off-by: pasta <pasta@dashboost.org> * instantsend: use auto in spots where possible and clear Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: make IsValidStructure const Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: divide by an integer to avoid double implicit conversions Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: make unused parameter unnamed Signed-off-by: pasta <pasta@dashboost.org> * quorums.* use const and use references where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums.h don't return const when returning by value Signed-off-by: pasta <pasta@dashboost.org> * quorums_blockprocessor.cpp remove redundant casts and combine two if statements Signed-off-by: pasta <pasta@dashboost.org> * quorums_blockprocessor.cpp make values const Signed-off-by: pasta <pasta@dashboost.org> * quorums_chainlocks.cpp access static function statically Signed-off-by: pasta <pasta@dashboost.org> * quorums_chainlocks.h remove commented out include Signed-off-by: pasta <pasta@dashboost.org> * quorums_commitment.cpp remove redundant casts Signed-off-by: pasta <pasta@dashboost.org> * quorums_debug.cpp remove redundant casts and add const Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsession.cpp use const where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp use const where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp don't use std::move which apparently prevents "copy elision" in this instance Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp use const Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionmgr.cpp misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_signing.* misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_signing_shares.* misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_utils.cpp misc refactoring Signed-off-by: pasta <pasta@dashboost.org>
2021-06-26 15:10:53 +02:00
vecStandardDenominations.push_back((COIN / 10) + 100);
vecStandardDenominations.push_back((COIN / 100) + 10);
vecStandardDenominations.push_back((COIN / 1000) + 1);
}
// check to make sure the collateral provided by the client is valid
bool CCoinJoin::IsCollateralValid(const CTransaction& txCollateral)
{
2018-11-05 10:29:07 +01:00
if (txCollateral.vout.empty()) return false;
if (txCollateral.nLockTime != 0) return false;
CAmount nValueIn = 0;
CAmount nValueOut = 0;
for (const auto& txout : txCollateral.vout) {
nValueOut += txout.nValue;
if (!txout.scriptPubKey.IsPayToPublicKeyHash() && !txout.scriptPubKey.IsUnspendable()) {
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- Invalid Script, txCollateral=%s", txCollateral.ToString()); /* Continued */
return false;
}
}
for (const auto& txin : txCollateral.vin) {
2017-09-26 16:33:46 +02:00
Coin coin;
auto mempoolTx = mempool.get(txin.prevout.hash);
if (mempoolTx != nullptr) {
if (mempool.isSpent(txin.prevout) || !llmq::quorumInstantSendManager->IsLocked(txin.prevout.hash)) {
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- spent or non-locked mempool input! txin=%s\n", txin.ToString());
return false;
}
nValueIn += mempoolTx->vout[txin.prevout.n].nValue;
} else if (GetUTXOCoin(txin.prevout, coin)) {
nValueIn += coin.out.nValue;
} else {
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- Unknown inputs in collateral transaction, txCollateral=%s", txCollateral.ToString()); /* Continued */
return false;
}
}
//collateral transactions are required to pay out a small fee to the miners
2018-11-05 10:29:07 +01:00
if (nValueIn - nValueOut < GetCollateralAmount()) {
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- did not include enough fees in transaction: fees: %d, txCollateral=%s", nValueOut - nValueIn, txCollateral.ToString()); /* Continued */
return false;
}
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- %s", txCollateral.ToString()); /* Continued */
{
LOCK(cs_main);
CValidationState validationState;
if (!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(txCollateral), nullptr /* pfMissingInputs */, false /* bypass_limits */, maxTxFee /* nAbsurdFee */, true /* fDryRun */)) {
LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n");
return false;
}
}
return true;
}
bool CCoinJoin::IsCollateralAmount(CAmount nInputAmount)
{
// collateral input can be anything between 1x and "max" (including both)
return (nInputAmount >= GetCollateralAmount() && nInputAmount <= GetMaxCollateralAmount());
}
Merge #12257: [wallet] Use destination groups instead of coins in coin select 232f96f5c8a3920c09db92f4dbac2ad7d10ce8cf doc: Add release notes for -avoidpartialspends (Karl-Johan Alm) e00b4699cc6d2ee5697d38dd6607eb2631c9b77a clean-up: Remove no longer used ivars from CInputCoin (Karl-Johan Alm) 43e04d13b1ffc02b1082176e87f420198b40c7b1 wallet: Remove deprecated OutputEligibleForSpending (Karl-Johan Alm) 0128121101fb3ee82f3abd3973a967a4226ffe0e test: Add basic testing for wallet groups (Karl-Johan Alm) 59d6f7b4e2f847ec1f2ff46c84e6157655984f85 wallet: Switch to using output groups instead of coins in coin selection (Karl-Johan Alm) 87ebce25d66952f5ce565bb5130dcf5e24049872 wallet: Add output grouping (Karl-Johan Alm) bb629cb9dc567cc819724d9f4852652926e60cbf Add -avoidpartialspends and m_avoid_partial_spends (Karl-Johan Alm) 65b3eda458221644616d0fdd6ba0fe01bdbce893 wallet: Add input bytes to CInputCoin (Karl-Johan Alm) a443d7a0ca333b0bae63e04b5d476f9ad9c7aeac moveonly: CoinElegibilityFilter into coinselection.h (Karl-Johan Alm) 173e18a289088c6087ba6fac708e322aa63b7a94 utils: Add insert() convenience templates (Karl-Johan Alm) Pull request description: This PR adds an optional (off by default) `-avoidpartialspends` flag, which changes coin select to use output groups rather than outputs, where each output group corresponds to all outputs with the same destination. It is a privacy improvement, as each time you spend some output, any other output that is publicly associated with the destination (address) will also be spent at the same time, at the cost of fee increase for cases where coin select without group restriction would find a more optimal set of coins (see example below). For regular use without address reuse, this PR should have no effect on the user experience whatsoever; it only affects users who, for some reason, have multiple outputs with the same destination (i.e. address reuse). Nodes with this turned off will still try to avoid partial spending, if the fee of the resulting transaction is not greater than the fee of the original transaction. Example: a node has four outputs linked to two addresses `A` and `B`: * 1.0 btc to `A` * 0.5 btc to `A` * 1.0 btc to `B` * 0.5 btc to `B` The node sends 0.2 btc to `C`. Without `-avoidpartialspends`, the following coin selection will occur: * 0.5 btc to `A` or `B` is picked * 0.2 btc is output to `C` * 0.3 - fee is output to (unique change address) With `-avoidpartialspends`, the following will instead happen: * Both of (0.5, 1.0) btc to `A` or `B` is picked (one or the other pair) * 0.2 btc is output to `C` * 1.3 - fee is output to (unique change address) As noted, the pro here is that, assuming nobody sends to the address after you spend from it, you will only ever use one address once. The con is that the transaction becomes slightly larger in this case, because it is overpicking outputs to adhere to the no partial spending rule. This complements #10386, in particular it addresses @luke-jr and @gmaxwell's concerns in https://github.com/bitcoin/bitcoin/pull/10386#issuecomment-300667926 and https://github.com/bitcoin/bitcoin/pull/10386#issuecomment-302361381. Together with `-avoidreuse`, this fully addresses the concerns in #10065 I believe. Tree-SHA512: 24687a4490ba59cf4198ed90052944ff4996653a4257833bb52ed24d058b3e924800c9b3790aeb6be6385b653b49e304453e5d7ff960e64c682fc23bfc447621 # Conflicts: # src/Makefile.am # src/bench/coin_selection.cpp # src/wallet/coincontrol.h # src/wallet/coinselection.cpp # src/wallet/coinselection.h # src/wallet/init.cpp # src/wallet/test/coinselector_tests.cpp # src/wallet/wallet.cpp # src/wallet/wallet.h # test/functional/test_runner.py
2018-07-24 15:06:21 +02:00
int CCoinJoin::CalculateAmountPriority(CAmount nInputAmount)
{
for (const auto& d : GetStandardDenominations()) {
// large denoms have lower value
if (nInputAmount == d) {
return (float)COIN / d * 10000;
}
}
if (nInputAmount < COIN) {
return 20000;
}
//nondenom return largest first
return -1 * (nInputAmount / COIN);
}
/*
Return a bitshifted integer representing a denomination in vecStandardDenominations
or 0 if none was found
*/
int CCoinJoin::AmountToDenomination(CAmount nInputAmount)
{
for (size_t i = 0; i < vecStandardDenominations.size(); ++i) {
if (nInputAmount == vecStandardDenominations[i]) {
return 1 << i;
}
}
return 0;
}
/*
Returns:
- one of standard denominations from vecStandardDenominations based on the provided bitshifted integer
- 0 for non-initialized sessions (nDenom = 0)
- a value below 0 if an error occured while converting from one to another
*/
CAmount CCoinJoin::DenominationToAmount(int nDenom)
{
if (nDenom == 0) {
// not initialized
return 0;
}
size_t nMaxDenoms = vecStandardDenominations.size();
if (nDenom >= (1 << nMaxDenoms) || nDenom < 0) {
// out of bounds
return -1;
}
if ((nDenom & (nDenom - 1)) != 0) {
// non-denom
return -2;
}
CAmount nDenomAmount{-3};
for (size_t i = 0; i < nMaxDenoms; ++i) {
2018-11-05 10:29:07 +01:00
if (nDenom & (1 << i)) {
nDenomAmount = vecStandardDenominations[i];
break;
}
}
return nDenomAmount;
}
/*
Same as DenominationToAmount but returns a string representation
*/
std::string CCoinJoin::DenominationToString(int nDenom)
{
CAmount nDenomAmount = DenominationToAmount(nDenom);
switch (nDenomAmount) {
case 0: return "N/A";
case -1: return "out-of-bounds";
case -2: return "non-denom";
case -3: return "to-amount-error";
default: return ValueFromAmount(nDenomAmount).getValStr();
}
// shouldn't happen
return "to-string-error";
}
bool CCoinJoin::IsDenominatedAmount(CAmount nInputAmount)
{
return AmountToDenomination(nInputAmount) > 0;
}
bool CCoinJoin::IsValidDenomination(int nDenom)
{
return DenominationToAmount(nDenom) > 0;
}
std::string CCoinJoin::GetMessageByID(PoolMessage nMessageID)
{
switch (nMessageID) {
2018-11-05 10:29:07 +01:00
case ERR_ALREADY_HAVE:
return _("Already have that input.");
case ERR_DENOM:
return _("No matching denominations found for mixing.");
case ERR_ENTRIES_FULL:
return _("Entries are full.");
case ERR_EXISTING_TX:
return _("Not compatible with existing transactions.");
case ERR_FEES:
return _("Transaction fees are too high.");
case ERR_INVALID_COLLATERAL:
return _("Collateral not valid.");
case ERR_INVALID_INPUT:
return _("Input is not valid.");
case ERR_INVALID_SCRIPT:
return _("Invalid script detected.");
case ERR_INVALID_TX:
return _("Transaction not valid.");
case ERR_MAXIMUM:
return _("Entry exceeds maximum size.");
case ERR_MN_LIST:
return _("Not in the Masternode list.");
case ERR_MODE:
return _("Incompatible mode.");
case ERR_QUEUE_FULL:
return _("Masternode queue is full.");
case ERR_RECENT:
return _("Last queue was created too recently.");
2018-11-05 10:29:07 +01:00
case ERR_SESSION:
return _("Session not complete!");
case ERR_MISSING_TX:
return _("Missing input transaction information.");
case ERR_VERSION:
return _("Incompatible version.");
case MSG_NOERR:
return _("No errors detected.");
case MSG_SUCCESS:
return _("Transaction created successfully.");
case MSG_ENTRIES_ADDED:
return _("Your entries added successfully.");
case ERR_SIZE_MISMATCH:
return _("Inputs vs outputs size mismatch.");
case ERR_NON_STANDARD_PUBKEY:
case ERR_NOT_A_MN:
2018-11-05 10:29:07 +01:00
default:
return _("Unknown response.");
}
}
void CCoinJoin::AddDSTX(const CCoinJoinBroadcastTx& dstx)
{
LOCK(cs_mapdstx);
mapDSTX.insert(std::make_pair(dstx.tx->GetHash(), dstx));
}
CCoinJoinBroadcastTx CCoinJoin::GetDSTX(const uint256& hash)
{
LOCK(cs_mapdstx);
auto it = mapDSTX.find(hash);
return (it == mapDSTX.end()) ? CCoinJoinBroadcastTx() : it->second;
}
void CCoinJoin::CheckDSTXes(const CBlockIndex* pindex)
{
LOCK(cs_mapdstx);
auto it = mapDSTX.begin();
2018-11-05 10:29:07 +01:00
while (it != mapDSTX.end()) {
if (it->second.IsExpired(pindex)) {
mapDSTX.erase(it++);
} else {
++it;
}
}
LogPrint(BCLog::COINJOIN, "CCoinJoin::CheckDSTXes -- mapDSTX.size()=%llu\n", mapDSTX.size());
}
void CCoinJoin::UpdatedBlockTip(const CBlockIndex* pindex)
{
if (pindex && masternodeSync.IsBlockchainSynced()) {
CheckDSTXes(pindex);
}
}
void CCoinJoin::NotifyChainLock(const CBlockIndex* pindex)
{
if (pindex && masternodeSync.IsBlockchainSynced()) {
CheckDSTXes(pindex);
}
}
void CCoinJoin::UpdateDSTXConfirmedHeight(const CTransactionRef& tx, int nHeight)
{
AssertLockHeld(cs_mapdstx);
auto it = mapDSTX.find(tx->GetHash());
if (it == mapDSTX.end()) {
return;
}
it->second.SetConfirmedHeight(nHeight);
LogPrint(BCLog::COINJOIN, "CCoinJoin::%s -- txid=%s, nHeight=%d\n", __func__, tx->GetHash().ToString(), nHeight);
}
void CCoinJoin::TransactionAddedToMempool(const CTransactionRef& tx)
{
LOCK(cs_mapdstx);
UpdateDSTXConfirmedHeight(tx, -1);
}
void CCoinJoin::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted)
{
LOCK(cs_mapdstx);
for (const auto& tx : vtxConflicted) {
UpdateDSTXConfirmedHeight(tx, -1);
}
for (const auto& tx : pblock->vtx) {
UpdateDSTXConfirmedHeight(tx, pindex->nHeight);
}
}
refactor: misc refactoring in instantsend, llmq, coinjoin (#4212) * instantsend: make stuff const where possible Signed-off-by: pasta <pasta@dashboost.org> * instantsend: remove unused `params` Signed-off-by: pasta <pasta@dashboost.org> * instantsend: combine two nested if's into one Signed-off-by: pasta <pasta@dashboost.org> * instantsend: use auto in spots where possible and clear Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: make IsValidStructure const Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: divide by an integer to avoid double implicit conversions Signed-off-by: pasta <pasta@dashboost.org> * coinjoin: make unused parameter unnamed Signed-off-by: pasta <pasta@dashboost.org> * quorums.* use const and use references where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums.h don't return const when returning by value Signed-off-by: pasta <pasta@dashboost.org> * quorums_blockprocessor.cpp remove redundant casts and combine two if statements Signed-off-by: pasta <pasta@dashboost.org> * quorums_blockprocessor.cpp make values const Signed-off-by: pasta <pasta@dashboost.org> * quorums_chainlocks.cpp access static function statically Signed-off-by: pasta <pasta@dashboost.org> * quorums_chainlocks.h remove commented out include Signed-off-by: pasta <pasta@dashboost.org> * quorums_commitment.cpp remove redundant casts Signed-off-by: pasta <pasta@dashboost.org> * quorums_debug.cpp remove redundant casts and add const Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsession.cpp use const where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp use const where possible Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp don't use std::move which apparently prevents "copy elision" in this instance Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionhandler.cpp use const Signed-off-by: pasta <pasta@dashboost.org> * quorums_dkgsessionmgr.cpp misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_signing.* misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_signing_shares.* misc refactoring Signed-off-by: pasta <pasta@dashboost.org> * quorums_utils.cpp misc refactoring Signed-off-by: pasta <pasta@dashboost.org>
2021-06-26 15:10:53 +02:00
void CCoinJoin::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex*)
{
LOCK(cs_mapdstx);
for (const auto& tx : pblock->vtx) {
UpdateDSTXConfirmedHeight(tx, -1);
}
}