2023-12-31 01:00:00 +01:00
// Copyright (c) 2014-2024 The Dash Core developers
2017-05-05 13:26:27 +02:00
// 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
2021-03-17 23:36:11 +01:00
# include <coinjoin/coinjoin.h>
2017-05-05 13:26:27 +02:00
2021-10-25 15:55:34 +02:00
# include <bls/bls.h>
2021-04-16 05:41:16 +02:00
# include <chain.h>
2021-10-25 15:55:34 +02:00
# include <chainparams.h>
# include <consensus/validation.h>
2023-12-01 13:26:25 +01:00
# include <governance/common.h>
2021-10-25 15:55:34 +02:00
# include <llmq/chainlocks.h>
# include <llmq/instantsend.h>
# include <masternode/node.h>
# include <masternode/sync.h>
2020-03-19 23:46:56 +01:00
# include <messagesigner.h>
# include <netmessagemaker.h>
# include <txmempool.h>
2021-06-27 08:33:13 +02:00
# include <util/moneystr.h>
2021-10-25 15:55:34 +02:00
# include <util/system.h>
2022-03-24 05:13:51 +01:00
# include <util/translation.h>
2020-03-19 23:46:56 +01:00
# include <validation.h>
2019-04-29 10:32:08 +02:00
refactor: re-order headers and forward declarations to improve compile time (#5693)
## Issue being fixed or feature implemented
Some headers include other heavy headers, such as `logging.h`,
`tinyformat.h`, `iostream`. These headers are heavy and increase
compilation time on scale of whole project drastically because can be
used in many other headers.
## What was done?
Moved many heavy includes from headers to cpp files to optimize
compilation time.
In some places added forward declarations if it is reasonable.
As side effect removed 2 circular dependencies:
```
"llmq/debug -> llmq/dkgsessionhandler -> llmq/debug"
"llmq/debug -> llmq/dkgsessionhandler -> llmq/dkgsession -> llmq/debug"
```
## How Has This Been Tested?
Run build 2 times before refactoring and after refactoring: `make clean
&& sleep 10s; time make -j18`
Before refactoring:
```
real 5m37,826s
user 77m12,075s
sys 6m20,547s
real 5m32,626s
user 76m51,143s
sys 6m24,511s
```
After refactoring:
```
real 5m18,509s
user 73m32,133s
sys 6m21,590s
real 5m14,466s
user 73m20,942s
sys 6m17,868s
```
~5% of improvement for compilation time. That's not huge, but that's
worth to get merged
There're several more refactorings TODO but better to do them later by
backports:
- bitcoin/bitcoin#27636
- bitcoin/bitcoin#26286
- bitcoin/bitcoin#27238
- and maybe this one: bitcoin/bitcoin#28200
## Breaking Changes
N/A
## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone
2023-11-17 17:04:18 +01:00
# include <tinyformat.h>
2018-07-12 11:02:20 +02:00
# include <string>
2017-05-05 13:26:27 +02:00
2021-12-12 14:38:12 +01:00
constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE { COIN / 10 } ;
2021-03-17 23:36:11 +01:00
bool CCoinJoinEntry : : AddScriptSig ( const CTxIn & txin )
2017-05-05 13:26:27 +02:00
{
2018-02-06 12:09:33 +01:00
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 ;
2017-05-05 13:26:27 +02:00
txdsin . scriptSig = txin . scriptSig ;
txdsin . fHasSig = true ;
return true ;
}
}
return false ;
}
2023-10-19 18:33:44 +02:00
uint256 CCoinJoinQueue : : GetSignatureHash ( ) const
2018-02-16 15:54:53 +01:00
{
2023-10-19 18:33:44 +02:00
return SerializeHash ( * this , SER_GETHASH , PROTOCOL_VERSION ) ;
2018-02-16 15:54:53 +01:00
}
2024-03-15 19:01:18 +01:00
bool CCoinJoinQueue : : Sign ( const CActiveMasternodeManager & mn_activeman )
2017-05-05 13:26:27 +02:00
{
2023-10-19 18:33:44 +02:00
uint256 hash = GetSignatureHash ( ) ;
2024-03-15 19:01:18 +01:00
CBLSSignature sig = mn_activeman . Sign ( hash , /*is_legacy=*/ false ) ;
2018-12-17 15:00:10 +01:00
if ( ! sig . IsValid ( ) ) {
return false ;
2017-06-30 20:30:16 +02:00
}
2023-10-19 18:33:44 +02:00
vchSig = sig . ToByteVector ( false ) ;
2017-06-30 20:30:16 +02:00
2018-02-16 15:54:53 +01:00
return true ;
2017-06-30 20:30:16 +02:00
}
2021-03-17 23:36:11 +01:00
bool CCoinJoinQueue : : CheckSignature ( const CBLSPublicKey & blsPubKey ) const
2017-06-30 20:30:16 +02:00
{
2023-10-19 18:33:44 +02:00
if ( ! CBLSSignature ( Span { vchSig } ) . VerifyInsecure ( blsPubKey , GetSignatureHash ( ) , false ) ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed \n " ) ;
2018-12-17 15:00:10 +01:00
return false ;
2017-06-30 20:30:16 +02:00
}
return true ;
}
2021-03-17 23:36:11 +01:00
bool CCoinJoinQueue : : Relay ( CConnman & connman )
2017-06-30 20:30:16 +02:00
{
2018-02-06 12:09:33 +01:00
connman . ForEachNode ( [ & connman , this ] ( CNode * pnode ) {
2020-06-05 09:22:53 +02:00
CNetMsgMaker msgMaker ( pnode - > GetCommonVersion ( ) ) ;
2022-04-12 20:03:12 +02:00
if ( pnode - > fSendDSQueue ) {
2016-11-25 20:01:56 +01:00
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : DSQUEUE , ( * this ) ) ) ;
2019-06-18 13:33:05 +02:00
}
2018-02-06 12:09:33 +01:00
} ) ;
2017-06-30 20:30:16 +02:00
return true ;
2017-05-05 13:26:27 +02:00
}
2022-02-11 17:15:26 +01:00
bool CCoinJoinQueue : : IsTimeOutOfBounds ( int64_t current_time ) const
2019-10-09 18:48:32 +02:00
{
2022-02-11 17:15:26 +01:00
return current_time - nTime > COINJOIN_QUEUE_TIMEOUT | |
nTime - current_time > COINJOIN_QUEUE_TIMEOUT ;
2019-10-09 18:48:32 +02:00
}
refactor: re-order headers and forward declarations to improve compile time (#5693)
## Issue being fixed or feature implemented
Some headers include other heavy headers, such as `logging.h`,
`tinyformat.h`, `iostream`. These headers are heavy and increase
compilation time on scale of whole project drastically because can be
used in many other headers.
## What was done?
Moved many heavy includes from headers to cpp files to optimize
compilation time.
In some places added forward declarations if it is reasonable.
As side effect removed 2 circular dependencies:
```
"llmq/debug -> llmq/dkgsessionhandler -> llmq/debug"
"llmq/debug -> llmq/dkgsessionhandler -> llmq/dkgsession -> llmq/debug"
```
## How Has This Been Tested?
Run build 2 times before refactoring and after refactoring: `make clean
&& sleep 10s; time make -j18`
Before refactoring:
```
real 5m37,826s
user 77m12,075s
sys 6m20,547s
real 5m32,626s
user 76m51,143s
sys 6m24,511s
```
After refactoring:
```
real 5m18,509s
user 73m32,133s
sys 6m21,590s
real 5m14,466s
user 73m20,942s
sys 6m17,868s
```
~5% of improvement for compilation time. That's not huge, but that's
worth to get merged
There're several more refactorings TODO but better to do them later by
backports:
- bitcoin/bitcoin#27636
- bitcoin/bitcoin#26286
- bitcoin/bitcoin#27238
- and maybe this one: bitcoin/bitcoin#28200
## Breaking Changes
N/A
## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone
2023-11-17 17:04:18 +01:00
[[nodiscard]] std : : string CCoinJoinQueue : : ToString ( ) const
{
return strprintf ( " nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s " ,
nDenom , nTime , fReady ? " true " : " false " , fTried ? " true " : " false " , masternodeOutpoint . ToStringShort ( ) ) ;
}
2023-10-19 18:33:44 +02:00
uint256 CCoinJoinBroadcastTx : : GetSignatureHash ( ) const
2018-02-16 15:54:53 +01:00
{
2023-10-19 18:33:44 +02:00
return SerializeHash ( * this , SER_GETHASH , PROTOCOL_VERSION ) ;
2018-02-16 15:54:53 +01:00
}
2024-03-15 19:01:18 +01:00
bool CCoinJoinBroadcastTx : : Sign ( const CActiveMasternodeManager & mn_activeman )
2017-06-30 20:30:16 +02:00
{
2023-10-19 18:33:44 +02:00
uint256 hash = GetSignatureHash ( ) ;
2024-03-15 19:01:18 +01:00
CBLSSignature sig = mn_activeman . Sign ( hash , /*is_legacy=*/ false ) ;
2018-12-17 13:40:29 +01:00
if ( ! sig . IsValid ( ) ) {
return false ;
2017-06-30 20:30:16 +02:00
}
2023-10-19 18:33:44 +02:00
vchSig = sig . ToByteVector ( false ) ;
2017-06-30 20:30:16 +02:00
2018-02-16 15:54:53 +01:00
return true ;
2017-06-30 20:30:16 +02:00
}
2021-03-17 23:36:11 +01:00
bool CCoinJoinBroadcastTx : : CheckSignature ( const CBLSPublicKey & blsPubKey ) const
2017-06-30 20:30:16 +02:00
{
2023-10-19 18:33:44 +02:00
if ( ! CBLSSignature ( Span { vchSig } ) . VerifyInsecure ( blsPubKey , GetSignatureHash ( ) , false ) ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBroadcastTx::CheckSignature -- VerifyInsecure() failed \n " ) ;
2018-12-17 13:40:29 +01:00
return false ;
2017-06-30 20:30:16 +02:00
}
return true ;
}
2022-09-22 13:14:48 +02:00
bool CCoinJoinBroadcastTx : : IsExpired ( const CBlockIndex * pindex , const llmq : : CChainLocksHandler & clhandler ) const
2017-07-10 16:42:09 +02:00
{
2019-07-07 00:07:03 +02:00
// expire confirmed DSTXes after ~1h since confirmation or chainlocked confirmation
2023-04-18 06:56:53 +02:00
if ( ! nConfirmedHeight . has_value ( ) | | pindex - > nHeight < * nConfirmedHeight ) return false ; // not mined yet
if ( pindex - > nHeight - * nConfirmedHeight > 24 ) return true ; // mined more than an hour ago
2022-09-22 13:14:48 +02:00
return clhandler . HasChainLock ( pindex - > nHeight , * pindex - > phashBlock ) ;
2017-07-10 16:42:09 +02:00
}
2021-06-26 15:10:53 +02:00
bool CCoinJoinBroadcastTx : : IsValidStructure ( ) const
2019-05-23 11:13:34 +02:00
{
// some trivial checks only
2023-01-12 04:24:29 +01:00
if ( masternodeOutpoint . IsNull ( ) & & m_protxHash . IsNull ( ) ) {
return false ;
}
2019-05-23 11:13:34 +02:00
if ( tx - > vin . size ( ) ! = tx - > vout . size ( ) ) {
return false ;
}
2024-01-09 18:25:58 +01:00
if ( tx - > vin . size ( ) < size_t ( CoinJoin : : GetMinPoolParticipants ( ) ) ) {
2019-05-23 11:13:34 +02:00
return false ;
}
2024-01-09 18:25:58 +01:00
if ( tx - > vin . size ( ) > CoinJoin : : GetMaxPoolParticipants ( ) * COINJOIN_ENTRY_MAX_SIZE ) {
2019-05-23 11:13:34 +02:00
return false ;
}
2021-12-21 13:05:29 +01:00
return ranges : : all_of ( tx - > vout , [ ] ( const auto & txOut ) {
2024-01-09 18:25:58 +01:00
return CoinJoin : : IsDenominatedAmount ( txOut . nValue ) & & txOut . scriptPubKey . IsPayToPublicKeyHash ( ) ;
2021-10-01 13:44:40 +02:00
} ) ;
2019-05-23 11:13:34 +02:00
}
2021-03-17 23:36:11 +01:00
void CCoinJoinBaseSession : : SetNull ( )
2017-05-05 13:26:27 +02:00
{
// Both sides
2022-04-25 11:28:37 +02:00
AssertLockHeld ( cs_coinjoin ) ;
2017-05-05 13:26:27 +02:00
nState = POOL_STATE_IDLE ;
nSessionID = 0 ;
nSessionDenom = 0 ;
vecEntries . clear ( ) ;
finalMutableTransaction . vin . clear ( ) ;
finalMutableTransaction . vout . clear ( ) ;
2018-02-12 13:47:53 +01:00
nTimeLastSuccessfulStep = GetTime ( ) ;
2017-05-05 13:26:27 +02:00
}
2021-03-17 23:36:11 +01:00
void CCoinJoinBaseManager : : SetNull ( )
2017-12-04 07:06:07 +01:00
{
2018-09-04 12:54:59 +02:00
LOCK ( cs_vecqueue ) ;
2021-03-17 23:36:11 +01:00
vecCoinJoinQueue . clear ( ) ;
2018-09-04 12:54:59 +02:00
}
2021-03-17 23:36:11 +01:00
void CCoinJoinBaseManager : : CheckQueue ( )
2018-09-04 12:54:59 +02:00
{
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
2017-12-04 07:06:07 +01:00
// check mixing queue objects for timeouts
2021-03-17 23:36:11 +01:00
auto it = vecCoinJoinQueue . begin ( ) ;
while ( it ! = vecCoinJoinQueue . end ( ) ) {
2022-02-11 17:15:26 +01:00
if ( it - > IsTimeOutOfBounds ( ) ) {
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseManager::%s -- Removing a queue (%s) \n " , __func__ , it - > ToString ( ) ) ;
2021-03-17 23:36:11 +01:00
it = vecCoinJoinQueue . erase ( it ) ;
2019-06-18 13:33:05 +02:00
} else {
2018-11-05 10:29:07 +01:00
+ + it ;
2019-06-18 13:33:05 +02:00
}
2017-12-04 07:06:07 +01:00
}
}
2021-03-17 23:36:11 +01:00
bool CCoinJoinBaseManager : : GetQueueItemAndTry ( CCoinJoinQueue & dsqRet )
2018-09-04 12:54:59 +02:00
{
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
2018-09-04 12:54:59 +02:00
2021-03-17 23:36:11 +01:00
for ( auto & dsq : vecCoinJoinQueue ) {
2018-09-04 12:54:59 +02:00
// only try each queue once
2019-10-09 18:48:32 +02:00
if ( dsq . fTried | | dsq . IsTimeOutOfBounds ( ) ) continue ;
2018-09-04 12:54:59 +02:00
dsq . fTried = true ;
dsqRet = dsq ;
return true ;
}
return false ;
}
2021-03-17 23:36:11 +01:00
std : : string CCoinJoinBaseSession : : GetStateString ( ) const
2017-05-05 13:26:27 +02:00
{
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 " ;
2017-05-05 13:26:27 +02:00
}
}
2020-09-07 09:47:14 +02:00
bool CCoinJoinBaseSession : : IsValidInOuts ( const CTxMemPool & mempool , const std : : vector < CTxIn > & vin , const std : : vector < CTxOut > & vout , PoolMessage & nMessageIDRet , bool * fConsumeCollateralRet ) const
2020-01-01 15:12:25 +01:00
{
std : : set < CScript > setScripPubKeys ;
nMessageIDRet = MSG_NOERR ;
if ( fConsumeCollateralRet ) * fConsumeCollateralRet = false ;
if ( vin . size ( ) ! = vout . size ( ) ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::%s -- ERROR: inputs vs outputs size mismatch! %d vs %d \n " , __func__ , vin . size ( ) , vout . size ( ) ) ;
2020-01-01 15:12:25 +01:00
nMessageIDRet = ERR_SIZE_MISMATCH ;
if ( fConsumeCollateralRet ) * fConsumeCollateralRet = true ;
return false ;
}
auto checkTxOut = [ & ] ( const CTxOut & txout ) {
2024-01-09 18:25:58 +01:00
if ( int nDenom = CoinJoin : : AmountToDenomination ( txout . nValue ) ; nDenom ! = nSessionDenom ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::IsValidInOuts -- ERROR: incompatible denom %d (%s) != nSessionDenom %d (%s) \n " ,
2024-01-09 18:25:58 +01:00
nDenom , CoinJoin : : DenominationToString ( nDenom ) , nSessionDenom , CoinJoin : : DenominationToString ( nSessionDenom ) ) ;
2020-01-01 15:12:25 +01:00
nMessageIDRet = ERR_DENOM ;
if ( fConsumeCollateralRet ) * fConsumeCollateralRet = true ;
return false ;
}
if ( ! txout . scriptPubKey . IsPayToPublicKeyHash ( ) ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::IsValidInOuts -- ERROR: invalid script! scriptPubKey=%s \n " , ScriptToAsmStr ( txout . scriptPubKey ) ) ;
2020-01-01 15:12:25 +01:00
nMessageIDRet = ERR_INVALID_SCRIPT ;
if ( fConsumeCollateralRet ) * fConsumeCollateralRet = true ;
return false ;
}
if ( ! setScripPubKeys . insert ( txout . scriptPubKey ) . second ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::IsValidInOuts -- ERROR: already have this script! scriptPubKey=%s \n " , ScriptToAsmStr ( txout . scriptPubKey ) ) ;
2020-01-01 15:12:25 +01:00
nMessageIDRet = ERR_ALREADY_HAVE ;
if ( fConsumeCollateralRet ) * fConsumeCollateralRet = true ;
return false ;
}
// IsPayToPublicKeyHash() above already checks for scriptPubKey size,
2021-07-30 02:01:02 +02:00
// no need to double-check, hence no usage of ERR_NON_STANDARD_PUBKEY
2020-01-01 15:12:25 +01:00
return true ;
} ;
CAmount nFees { 0 } ;
for ( const auto & txout : vout ) {
if ( ! checkTxOut ( txout ) ) {
return false ;
}
nFees - = txout . nValue ;
}
2022-05-07 17:46:33 +02:00
CCoinsViewMemPool viewMemPool ( WITH_LOCK ( cs_main , return & : : ChainstateActive ( ) . CoinsTip ( ) ) , mempool ) ;
2020-01-01 15:12:25 +01:00
for ( const auto & txin : vin ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::%s -- txin=%s \n " , __func__ , txin . ToString ( ) ) ;
2020-01-01 15:12:25 +01:00
if ( txin . prevout . IsNull ( ) ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::%s -- ERROR: invalid input! \n " , __func__ ) ;
2020-01-01 15:12:25 +01:00
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 ) ) ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::%s -- ERROR: missing, spent or non-locked mempool input! txin=%s \n " , __func__ , txin . ToString ( ) ) ;
2020-01-01 15:12:25 +01:00
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,
2021-07-30 02:01:02 +02:00
// no need to double-check. If not, we are doing something wrong, bail out.
2020-01-01 15:12:25 +01:00
if ( nFees ! = 0 ) {
2021-03-17 23:36:11 +01:00
LogPrint ( BCLog : : COINJOIN , " CCoinJoinBaseSession::%s -- ERROR: non-zero fees! fees: %lld \n " , __func__ , nFees ) ;
2020-01-01 15:12:25 +01:00
nMessageIDRet = ERR_FEES ;
return false ;
}
return true ;
}
2024-01-25 07:53:18 +01:00
// Responsibility for checking fee sanity is moved from the mempool to the client (BroadcastTransaction)
// but CoinJoin still requires ATMP with fee sanity checks so we need to implement them separately
2024-02-01 20:18:49 +01:00
bool ATMPIfSaneFee ( CChainState & active_chainstate , CTxMemPool & pool , const CTransactionRef & tx , bool test_accept ) {
2024-01-25 07:53:18 +01:00
AssertLockHeld ( cs_main ) ;
2024-02-01 20:18:49 +01:00
const MempoolAcceptResult result = AcceptToMemoryPool ( active_chainstate , pool , tx , /* bypass_limits */ false , /* test_accept */ true ) ;
if ( result . m_result_type ! = MempoolAcceptResult : : ResultType : : VALID ) {
2024-01-25 07:53:18 +01:00
/* Fetch fee and fast-fail if ATMP fails regardless */
return false ;
2024-02-01 20:18:49 +01:00
} else if ( result . m_base_fees . value ( ) > DEFAULT_MAX_RAW_TX_FEE ) {
2024-01-25 07:53:18 +01:00
/* Check fee against fixed upper limit */
return false ;
} else if ( test_accept ) {
/* Don't re-run ATMP if only doing test run */
return true ;
}
2024-02-01 20:18:49 +01:00
return AcceptToMemoryPool ( active_chainstate , pool , tx , /* bypass_limits */ false , test_accept ) . m_result_type = = MempoolAcceptResult : : ResultType : : VALID ;
2024-01-25 07:53:18 +01:00
}
2017-05-05 13:26:27 +02:00
// check to make sure the collateral provided by the client is valid
2024-01-09 18:25:58 +01:00
bool CoinJoin : : IsCollateralValid ( CTxMemPool & mempool , const CTransaction & txCollateral )
2017-05-05 13:26:27 +02:00
{
2018-11-05 10:29:07 +01:00
if ( txCollateral . vout . empty ( ) ) return false ;
if ( txCollateral . nLockTime ! = 0 ) return false ;
2017-05-05 13:26:27 +02:00
CAmount nValueIn = 0 ;
CAmount nValueOut = 0 ;
2018-02-06 12:09:33 +01:00
for ( const auto & txout : txCollateral . vout ) {
2017-05-05 13:26:27 +02:00
nValueOut + = txout . nValue ;
2018-11-07 08:39:25 +01:00
if ( ! txout . scriptPubKey . IsPayToPublicKeyHash ( ) & & ! txout . scriptPubKey . IsUnspendable ( ) ) {
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::IsCollateralValid -- Invalid Script, txCollateral=%s " , txCollateral . ToString ( ) ) ; /* Continued */
2017-05-05 13:26:27 +02:00
return false ;
}
}
2018-02-06 12:09:33 +01:00
for ( const auto & txin : txCollateral . vin ) {
2017-09-26 16:33:46 +02:00
Coin coin ;
2019-04-29 10:32:08 +02:00
auto mempoolTx = mempool . get ( txin . prevout . hash ) ;
if ( mempoolTx ! = nullptr ) {
if ( mempool . isSpent ( txin . prevout ) | | ! llmq : : quorumInstantSendManager - > IsLocked ( txin . prevout . hash ) ) {
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::IsCollateralValid -- spent or non-locked mempool input! txin=%s \n " , txin . ToString ( ) ) ;
2019-04-29 10:32:08 +02:00
return false ;
}
nValueIn + = mempoolTx - > vout [ txin . prevout . n ] . nValue ;
} else if ( GetUTXOCoin ( txin . prevout , coin ) ) {
nValueIn + = coin . out . nValue ;
} else {
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::IsCollateralValid -- Unknown inputs in collateral transaction, txCollateral=%s " , txCollateral . ToString ( ) ) ; /* Continued */
2017-08-25 14:56:48 +02:00
return false ;
2017-05-05 13:26:27 +02:00
}
}
2017-06-30 20:30:16 +02:00
//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 ( ) ) {
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::IsCollateralValid -- did not include enough fees in transaction: fees: %d, txCollateral=%s " , nValueOut - nValueIn , txCollateral . ToString ( ) ) ; /* Continued */
2017-05-05 13:26:27 +02:00
return false ;
}
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::IsCollateralValid -- %s " , txCollateral . ToString ( ) ) ; /* Continued */
2017-05-05 13:26:27 +02:00
{
LOCK ( cs_main ) ;
2024-02-01 20:18:49 +01:00
if ( ! ATMPIfSaneFee ( : : ChainstateActive ( ) , mempool , MakeTransactionRef ( txCollateral ) , /*test_accept=*/ true ) ) {
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool() \n " ) ;
2017-05-05 13:26:27 +02:00
return false ;
}
}
return true ;
}
2024-01-09 18:25:58 +01:00
bilingual_str CoinJoin : : GetMessageByID ( PoolMessage nMessageID )
2017-05-05 13:26:27 +02:00
{
switch ( nMessageID ) {
2018-11-05 10:29:07 +01:00
case ERR_ALREADY_HAVE :
2022-04-06 22:37:20 +02:00
return _ ( " Already have that input. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_DENOM :
2022-04-06 22:37:20 +02:00
return _ ( " No matching denominations found for mixing. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_ENTRIES_FULL :
2022-04-06 22:37:20 +02:00
return _ ( " Entries are full. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_EXISTING_TX :
2022-04-06 22:37:20 +02:00
return _ ( " Not compatible with existing transactions. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_FEES :
2022-04-06 22:37:20 +02:00
return _ ( " Transaction fees are too high. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_INVALID_COLLATERAL :
2022-04-06 22:37:20 +02:00
return _ ( " Collateral not valid. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_INVALID_INPUT :
2022-04-06 22:37:20 +02:00
return _ ( " Input is not valid. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_INVALID_SCRIPT :
2022-04-06 22:37:20 +02:00
return _ ( " Invalid script detected. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_INVALID_TX :
2022-04-06 22:37:20 +02:00
return _ ( " Transaction not valid. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_MAXIMUM :
2022-04-06 22:37:20 +02:00
return _ ( " Entry exceeds maximum size. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_MN_LIST :
2022-04-06 22:37:20 +02:00
return _ ( " Not in the Masternode list. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_MODE :
2022-04-06 22:37:20 +02:00
return _ ( " Incompatible mode. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_QUEUE_FULL :
2022-04-06 22:37:20 +02:00
return _ ( " Masternode queue is full. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_RECENT :
2022-04-06 22:37:20 +02:00
return _ ( " Last queue was created too recently. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_SESSION :
2022-04-06 22:37:20 +02:00
return _ ( " Session not complete! " ) ;
2018-11-05 10:29:07 +01:00
case ERR_MISSING_TX :
2022-04-06 22:37:20 +02:00
return _ ( " Missing input transaction information. " ) ;
2018-11-05 10:29:07 +01:00
case ERR_VERSION :
2022-04-06 22:37:20 +02:00
return _ ( " Incompatible version. " ) ;
2018-11-05 10:29:07 +01:00
case MSG_NOERR :
2022-04-06 22:37:20 +02:00
return _ ( " No errors detected. " ) ;
2018-11-05 10:29:07 +01:00
case MSG_SUCCESS :
2022-04-06 22:37:20 +02:00
return _ ( " Transaction created successfully. " ) ;
2018-11-05 10:29:07 +01:00
case MSG_ENTRIES_ADDED :
2022-04-06 22:37:20 +02:00
return _ ( " Your entries added successfully. " ) ;
2019-05-23 11:13:34 +02:00
case ERR_SIZE_MISMATCH :
2022-04-06 22:37:20 +02:00
return _ ( " Inputs vs outputs size mismatch. " ) ;
2020-01-01 15:12:25 +01:00
case ERR_NON_STANDARD_PUBKEY :
case ERR_NOT_A_MN :
2018-11-05 10:29:07 +01:00
default :
2022-04-06 22:37:20 +02:00
return _ ( " Unknown response. " ) ;
2017-05-05 13:26:27 +02:00
}
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : AddDSTX ( const CCoinJoinBroadcastTx & dstx )
2017-05-05 13:26:27 +02:00
{
2022-04-25 11:28:37 +02:00
AssertLockNotHeld ( cs_mapdstx ) ;
2017-06-30 20:30:16 +02:00
LOCK ( cs_mapdstx ) ;
2017-09-20 14:02:53 +02:00
mapDSTX . insert ( std : : make_pair ( dstx . tx - > GetHash ( ) , dstx ) ) ;
2017-05-05 13:26:27 +02:00
}
2023-12-12 19:57:41 +01:00
CCoinJoinBroadcastTx CDSTXManager : : GetDSTX ( const uint256 & hash )
2017-05-05 13:26:27 +02:00
{
2022-04-25 11:28:37 +02:00
AssertLockNotHeld ( cs_mapdstx ) ;
2017-06-30 20:30:16 +02:00
LOCK ( cs_mapdstx ) ;
auto it = mapDSTX . find ( hash ) ;
2021-03-17 23:36:11 +01:00
return ( it = = mapDSTX . end ( ) ) ? CCoinJoinBroadcastTx ( ) : it - > second ;
2017-05-05 13:26:27 +02:00
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : CheckDSTXes ( const CBlockIndex * pindex , const llmq : : CChainLocksHandler & clhandler )
2017-07-10 16:42:09 +02:00
{
2022-04-25 11:28:37 +02:00
AssertLockNotHeld ( cs_mapdstx ) ;
2017-07-10 16:42:09 +02:00
LOCK ( cs_mapdstx ) ;
2019-06-18 13:33:05 +02:00
auto it = mapDSTX . begin ( ) ;
2018-11-05 10:29:07 +01:00
while ( it ! = mapDSTX . end ( ) ) {
2022-09-22 13:14:48 +02:00
if ( it - > second . IsExpired ( pindex , clhandler ) ) {
2017-07-10 16:42:09 +02:00
mapDSTX . erase ( it + + ) ;
} else {
+ + it ;
}
}
2024-01-09 18:25:58 +01:00
LogPrint ( BCLog : : COINJOIN , " CoinJoin::CheckDSTXes -- mapDSTX.size()=%llu \n " , mapDSTX . size ( ) ) ;
2017-07-10 16:42:09 +02:00
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : UpdatedBlockTip ( const CBlockIndex * pindex , const llmq : : CChainLocksHandler & clhandler , const CMasternodeSync & mn_sync )
2017-12-07 10:42:47 +01:00
{
2023-06-04 22:26:23 +02:00
if ( pindex & & mn_sync . IsBlockchainSynced ( ) ) {
2022-09-22 13:14:48 +02:00
CheckDSTXes ( pindex , clhandler ) ;
2017-12-07 10:42:47 +01:00
}
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : NotifyChainLock ( const CBlockIndex * pindex , const llmq : : CChainLocksHandler & clhandler , const CMasternodeSync & mn_sync )
2020-01-22 11:35:31 +01:00
{
2023-06-04 22:26:23 +02:00
if ( pindex & & mn_sync . IsBlockchainSynced ( ) ) {
2022-09-22 13:14:48 +02:00
CheckDSTXes ( pindex , clhandler ) ;
2020-01-22 11:35:31 +01:00
}
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : UpdateDSTXConfirmedHeight ( const CTransactionRef & tx , std : : optional < int > nHeight )
2017-07-10 16:42:09 +02:00
{
2019-05-27 16:22:09 +02:00
AssertLockHeld ( cs_mapdstx ) ;
2017-07-10 16:42:09 +02:00
2019-05-27 16:23:19 +02:00
auto it = mapDSTX . find ( tx - > GetHash ( ) ) ;
if ( it = = mapDSTX . end ( ) ) {
return ;
}
2017-07-10 16:42:09 +02:00
2019-05-27 16:23:19 +02:00
it - > second . SetConfirmedHeight ( nHeight ) ;
2023-12-12 19:57:41 +01:00
LogPrint ( BCLog : : COINJOIN , " CDSTXManager::%s -- txid=%s, nHeight=%d \n " , __func__ , tx - > GetHash ( ) . ToString ( ) , nHeight . value_or ( - 1 ) ) ;
2019-05-27 16:22:09 +02:00
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : TransactionAddedToMempool ( const CTransactionRef & tx )
2019-05-27 16:22:09 +02:00
{
2022-04-25 11:28:37 +02:00
AssertLockNotHeld ( cs_mapdstx ) ;
2019-05-27 16:22:09 +02:00
LOCK ( cs_mapdstx ) ;
2023-04-18 06:56:53 +02:00
UpdateDSTXConfirmedHeight ( tx , std : : nullopt ) ;
2019-05-27 16:22:09 +02:00
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : BlockConnected ( const std : : shared_ptr < const CBlock > & pblock , const CBlockIndex * pindex )
2019-05-27 16:22:09 +02:00
{
2022-04-25 11:28:37 +02:00
AssertLockNotHeld ( cs_mapdstx ) ;
2019-05-27 16:22:09 +02:00
LOCK ( cs_mapdstx ) ;
for ( const auto & tx : pblock - > vtx ) {
UpdateDSTXConfirmedHeight ( tx , pindex - > nHeight ) ;
}
}
2023-12-12 19:57:41 +01:00
void CDSTXManager : : BlockDisconnected ( const std : : shared_ptr < const CBlock > & pblock , const CBlockIndex * )
2019-05-27 16:22:09 +02:00
{
2022-04-25 11:28:37 +02:00
AssertLockNotHeld ( cs_mapdstx ) ;
2019-05-27 16:22:09 +02:00
LOCK ( cs_mapdstx ) ;
for ( const auto & tx : pblock - > vtx ) {
2023-04-18 06:56:53 +02:00
UpdateDSTXConfirmedHeight ( tx , std : : nullopt ) ;
2019-05-27 16:22:09 +02:00
}
2017-07-10 16:42:09 +02:00
}
2021-10-25 15:55:34 +02:00
2024-01-09 18:25:58 +01:00
int CoinJoin : : GetMinPoolParticipants ( ) { return Params ( ) . PoolMinParticipants ( ) ; }
int CoinJoin : : GetMaxPoolParticipants ( ) { return Params ( ) . PoolMaxParticipants ( ) ; }