diff --git a/dash-docs/protocol-documentation.md b/dash-docs/protocol-documentation.md index 3f5e82db01..743a55c37a 100644 --- a/dash-docs/protocol-documentation.md +++ b/dash-docs/protocol-documentation.md @@ -69,52 +69,6 @@ Bitcoin Public Key https://bitcoin.org/en/glossary/public-key ## Message Types -### MNANNOUNCE - "mnb" - -CMasternodeBroadcast - -Whenever a masternode comes online or a client is syncing, they will send this message which describes the masternode entry and how to validate messages from it. - -| Field Size | Field Name | Data type | Description | -| ---------- | ----------- | --------- | ---------- | -| 36 | outpoint | [COutPoint](#coutpoint) | The unspent output which is holding 1000 DASH -| # | addr | [CService](#cservice) | IPv4 address of the masternode -| 33-65 | pubKeyCollateralAddress | [CPubKey](#cpubkey) | CPubKey of the main 1000 DASH unspent output -| 33-65 | pubKeyMasternode | [CPubKey](#cpubkey) | CPubKey of the secondary signing key (For all other messaging other than announce message) -| 71-73 | sig | char[] | Signature of this message (verifiable via pubKeyCollateralAddress) -| 8 | sigTime | int64_t | Time which the signature was created -| 4 | nProtocolVersion | int | The protocol version of the masternode -| # | lastPing | [CMasternodePing](#mnping---mnp) | The last known ping of the masternode - -### MNPING - "mnp" - -CMasternodePing - -Every few minutes, masternodes ping the network with a message that propagates the whole network. - -| Field Size | Field Name | Data type | Description | -| ---------- | ----------- | --------- | --------- | -| 36 | masternodeOutpoint | [COutPoint](#coutpoint) | The unspent output of the masternode which is signing the message -| 32 | blockHash | uint256 | Current chaintip blockhash minus 12 -| 8 | sigTime | int64_t | Signature time for this ping -| 71-73 | vchSig | char[] | Signature of this message by masternode (verifiable via pubKeyMasternode) -| 1 | fSentinelIsCurrent | bool | true if last sentinel ping was current -| 4 | nSentinelVersion | uint32_t | The version of Sentinel running on the masternode which is signing the message -| 4 | nDaemonVersion | uint32_t | The version of dashd of the masternode which is signing the message (i.e. CLIENT_VERSION) - -### MASTERNODEPAYMENTVOTE - "mnw" - -CMasternodePaymentVote - -When a new block is found on the network, a masternode quorum will be determined and those 10 selected masternodes will issue a masternode payment vote message to pick the next winning node. - -| Field Size | Field Name | Data type | Description | -| ---------- | ----------- | --------- | ---------- | -| 36 | masternodeOutpoint | [COutPoint](#coutpoint) | The unspent output of the masternode which is signing the message -| 4 | nBlockHeight | int | The blockheight which the payee should be paid -| ? | payeeAddress | CScript | The address to pay to -| 71-73 | sig | char[] | Signature of the masternode which is signing the message - ### DSTX - "dstx" CDarksendBroadcastTx @@ -265,26 +219,6 @@ Spork ## Undocumented messages -### MASTERNODEPAYMENTBLOCK - "mnwb" - -Masternode Payment Block - -*NOTE: Per src/protocol.cpp, there is no message for this (only inventory)* - -### MNVERIFY - "mnv" - -Masternode Verify - -| Field Size | Field Name | Data type | Description | -| ---------- | ----------- | --------- | ---------- | -| 36 | masternodeOutpoint1 | [COutPoint](#coutpoint) | The unspent output which is holding 1000 DASH for masternode 1 -| 36 | masternodeOutpoint2 | [COutPoint](#coutpoint) | The unspent output which is holding 1000 DASH for masternode 2 -| # | addr | [CService](#cservice) | IPv4 address / port of the masternode -| 4 | nonce | int | Nonce -| 4 | nBlockHeight | int | The blockheight -| 66* | vchSig1 | char[] | Signature of by masternode 1 (unclear if 66 is the correct size, but this is what it appears to be in most cases) -| 66* | vchSig2 | char[] | Signature of by masternode 2 (unclear if 66 is the correct size, but this is what it appears to be in most cases) - ### DSFINALTX - "dsf" Darksend Final Transaction @@ -312,16 +246,6 @@ Governance Sync | 32 | nHash | uint256 | | | # | filter | CBloomFilter | | -### DSEG - "dseg" - -Masternode List/Entry Sync - -Get Masternode list or specific entry - -| Field Size | Field Name | Data type | Description | -| ---------- | ----------- | --------- | ---------- | -| 36 | masternodeOutpoint | [COutPoint](#coutpoint) | The unspent output which is holding 1000 DASH - ### SYNCSTATUSCOUNT - "ssc" Sync Status Count @@ -335,18 +259,6 @@ Sync Status Count | Item ID | Name | Description | | ---------- | ---------- | ----------- | -| 2 | MASTERNODE_SYNC_LIST | | -| 3 | MASTERNODE_SYNC_MNW | | | 4 | MASTERNODE_SYNC_GOVERNANCE | | | 10 | MASTERNODE_SYNC_GOVOBJ | | | 11 | MASTERNODE_SYNC_GOVOBJ_VOTE | | - -### MASTERNODEPAYMENTSYNC - "mnget" - -Masternode Payment Sync - -| Field Size | Field Name | Data type | Description | -| ---------- | ----------- | --------- | ---------- | -| 4 | nMnCount | int | | (DEPRECATED) - -*NOTE: There are no fields in this mesasge starting from protocol 70209* diff --git a/doc/files.md b/doc/files.md index ce12114963..8326c4e661 100644 --- a/doc/files.md +++ b/doc/files.md @@ -12,9 +12,7 @@ * fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0 * mempool.dat: dump of the mempool's transactions; since 0.14.0. * governance.dat: stores data for governance obgects -* masternode.conf: contains configuration settings for remote masternodes * mncache.dat: stores data for masternode list -* mnpayments.dat: stores data for masternode payments * netfulfilled.dat: stores data about recently made network requests * peers.dat: peer IP address database (custom format); since 0.7.0 * wallet.dat: personal wallet (BDB) with keys and transactions diff --git a/doc/guide-startmany.md b/doc/guide-startmany.md deleted file mode 100644 index d5aee4a430..0000000000 --- a/doc/guide-startmany.md +++ /dev/null @@ -1,133 +0,0 @@ -# start-many Setup Guide - -## Setting up your Wallet - -### Create New Wallet Addresses - -1. Open the QT Wallet. -2. Click the Receive tab. -3. Fill in the form to request a payment. - * Label: mn01 - * Amount: 1000 (optional) - * Click *Request payment* button -5. Click the *Copy Address* button - -Create a new wallet address for each Masternode. - -Close your QT Wallet. - -### Send 1000 DASH to New Addresses - -Send exactly 1000 DASH to each new address created above. - -### Create New Masternode Private Keys - -Open your QT Wallet and go to console (from the menu select `Tools` => `Debug Console`) - -Issue the following: - -```masternode genkey``` - -*Note: A masternode private key will need to be created for each Masternode you run. You should not use the same masternode private key for multiple Masternodes.* - -Close your QT Wallet. - -## Create masternode.conf file - -Remember... this is local. Make sure your QT is not running. - -Create the `masternode.conf` file in the same directory as your `wallet.dat`. - -Copy the masternode private key and correspondig collateral output transaction that holds the 1000 DASH. - -*Note: The masternode priviate key is **not** the same as a wallet private key. **Never** put your wallet private key in the masternode.conf file. That is almost equivalent to putting your 1000 DASH on the remote server and defeats the purpose of a hot/cold setup.* - -### Get the collateral output - -Open your QT Wallet and go to console (from the menu select `Tools` => `Debug Console`) - -Issue the following: - -```masternode outputs``` - -Make note of the hash (which is your collateral_output) and index. - -### Enter your Masternode details into your masternode.conf file -[From the dash github repo](https://github.com/dashpay/dash/blob/master/doc/masternode_conf.md) - -`masternode.conf` format is a space seperated text file. Each line consisting of an alias, IP address followed by port, masternode private key, collateral output transaction id and collateral output index. - -``` -alias ipaddress:port masternode_private_key collateral_output collateral_output_index -``` - -Example: - -``` -mn01 127.0.0.1:9999 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0 -mn02 127.0.0.2:9999 93WaAb3htPJEV8E9aQcN23Jt97bPex7YvWfgMDTUdWJvzmrMqey aa9f1034d973377a5e733272c3d0eced1de22555ad45d6b24abadff8087948d4 0 -``` - -## Update dash.conf on server - -If you generated a new masternode private key, you will need to update the remote `dash.conf` files. - -Shut down the daemon and then edit the file. - -```nano .dashcore/dash.conf``` - -### Edit the masternodeprivkey -If you generated a new masternode private key, you will need to update the `masternodeprivkey` value in your remote `dash.conf` file. - -## Start your Masternodes - -### Remote - -If your remote server is not running, start your remote daemon as you normally would. - -You can confirm that remote server is on the correct block by issuing - -```dash-cli getinfo``` - -and comparing with the official explorer at https://explorer.dash.org/chain/Dash - -### Local - -Finally... time to start from local. - -#### Open up your QT Wallet - -From the menu select `Tools` => `Debug Console` - -If you want to review your `masternode.conf` setting before starting Masternodes, issue the following in the Debug Console: - -```masternode list-conf``` - -Give it the eye-ball test. If satisfied, you can start your Masternodes one of two ways. - -1. `masternode start-alias [alias_from_masternode.conf]` -Example ```masternode start-alias mn01``` -2. `masternode start-many` - -## Verify that Masternodes actually started - -### Remote - -Issue command `masternode status` -It should return you something like that: -``` -dash-cli masternode status -{ - "outpoint" : "-", - "service" : ":", - "pubkey" : "<1000 DASH address>", - "status" : "Masternode successfully started" -} -``` -Command output should have "_Masternode successfully started_" in its `status` field now. If it says "_not capable_" instead, you should check your config again. - -### Local - -Search your Masternodes on https://dashninja.pl/masternodes.html - -_Hint: Bookmark it, you definitely will be using this site a lot._ diff --git a/doc/masternode-budget.md b/doc/masternode-budget.md index 28feee0079..c4cc31daaa 100644 --- a/doc/masternode-budget.md +++ b/doc/masternode-budget.md @@ -147,7 +147,7 @@ The following RPC commands are supported: - nextsuperblocksize - Get superblock size for a given blockheight - projection - Show the projection of which proposals will be paid the next cycle - vote - Vote on a proposal by single masternode (using dash.conf setup) - - vote-many - Vote on a proposal by all masternodes (using masternode.conf setup) + - vote-many - Vote on a proposal by all masternodes for which the voting key is in the wallet - vote-alias - Vote on a proposal by alias - mnfinalbudget "command"... ( "passphrase" ) - vote-many - Vote on a finalized budget diff --git a/doc/masternode_conf.md b/doc/masternode_conf.md deleted file mode 100644 index 6e2db264fa..0000000000 --- a/doc/masternode_conf.md +++ /dev/null @@ -1,29 +0,0 @@ -Masternode config -======================= - -Dash Core allows controlling multiple remote masternodes from a single wallet. The wallet needs to have a valid collateral output of 1000 coins for each masternode and uses a configuration file named `masternode.conf` which can be found in the following data directory (depending on your operating system): - * Windows: %APPDATA%\DashCore\ - * Mac OS: ~/Library/Application Support/DashCore/ - * Unix/Linux: ~/.dashcore/ - -`masternode.conf` is a space separated text file. Each line consists of an alias, IP address followed by port, masternode private key, collateral output transaction id and collateral output index. - -Example: -``` -mn1 127.0.0.2:19999 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 7603c20a05258c208b58b0a0d77603b9fc93d47cfa403035f87f3ce0af814566 0 -mn2 127.0.0.4:19999 92Da1aYg6sbenP6uwskJgEY2XWB5LwJ7bXRqc3UPeShtHWJDjDv 5d898e78244f3206e0105f421cdb071d95d111a51cd88eb5511fc0dbf4bfd95f 1 -``` - -In the example above: -* the collateral of 1000 DASH for `mn1` is output `0` of transaction [7603c20a05258c208b58b0a0d77603b9fc93d47cfa403035f87f3ce0af814566](https://test.explorer.dash.org/tx/7603c20a05258c208b58b0a0d77603b9fc93d47cfa403035f87f3ce0af814566) -* the collateral of 1000 DASH for `mn2` is output `1` of transaction [5d898e78244f3206e0105f421cdb071d95d111a51cd88eb5511fc0dbf4bfd95f](https://test.explorer.dash.org/tx/5d898e78244f3206e0105f421cdb071d95d111a51cd88eb5511fc0dbf4bfd95f) - -_Note: IPs like 127.0.0.* are not allowed actually, we are using them here for explanatory purposes only. Make sure you have real reachable remote IPs in you `masternode.conf`._ - -The following RPC commands are available (type `help masternode` in Console for more info): -* list-conf -* start-alias \ -* start-all -* start-missing -* start-disabled -* outputs diff --git a/src/Makefile.am b/src/Makefile.am index deecee050b..434076d1a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -148,7 +148,6 @@ BITCOIN_CORE_H = \ masternode-payments.h \ masternode-sync.h \ masternodeman.h \ - masternodeconfig.h \ memusage.h \ merkleblock.h \ messagesigner.h \ @@ -256,7 +255,6 @@ libdash_server_a_SOURCES = \ masternode.cpp \ masternode-payments.cpp \ masternode-sync.cpp \ - masternodeconfig.cpp \ masternodeman.cpp \ merkleblock.cpp \ messagesigner.cpp \ diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index bc80f0ec2a..d6f3d5f617 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -14,7 +14,6 @@ // Keep track of the active Masternode CActiveMasternodeInfo activeMasternodeInfo; -CActiveLegacyMasternodeManager legacyActiveMasternodeManager; CActiveDeterministicMasternodeManager* activeMasternodeManager; std::string CActiveDeterministicMasternodeManager::GetStateString() const @@ -161,7 +160,7 @@ void CActiveDeterministicMasternodeManager::UpdatedBlockTip(const CBlockIndex* p bool CActiveDeterministicMasternodeManager::GetLocalAddress(CService& addrRet) { // First try to find whatever local address is specified by externalip option - bool fFoundLocal = GetLocal(addrRet) && CMasternode::IsValidNetAddr(addrRet); + bool fFoundLocal = GetLocal(addrRet) && IsValidNetAddr(addrRet); if (!fFoundLocal && Params().NetworkIDString() == CBaseChainParams::REGTEST) { if (Lookup("127.0.0.1", addrRet, GetListenPort(), false)) { fFoundLocal = true; @@ -173,7 +172,7 @@ bool CActiveDeterministicMasternodeManager::GetLocalAddress(CService& addrRet) g_connman->ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty](CNode* pnode) { empty = false; if (pnode->addr.IsIPv4()) - fFoundLocal = GetLocal(activeMasternodeInfo.service, &pnode->addr) && CMasternode::IsValidNetAddr(activeMasternodeInfo.service); + fFoundLocal = GetLocal(activeMasternodeInfo.service, &pnode->addr) && IsValidNetAddr(activeMasternodeInfo.service); return !fFoundLocal; }); // nothing and no live connections, can't do anything for now @@ -186,275 +185,10 @@ bool CActiveDeterministicMasternodeManager::GetLocalAddress(CService& addrRet) return true; } -/********* LEGACY *********/ - -void CActiveLegacyMasternodeManager::ManageState(CConnman& connman) +bool CActiveDeterministicMasternodeManager::IsValidNetAddr(CService addrIn) { - if (deterministicMNManager->IsDIP3Active()) return; - - LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageState -- Start\n"); - if (!fMasternodeMode) { - LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageState -- Not a masternode, returning\n"); - return; - } - if (Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) { - nState = ACTIVE_MASTERNODE_SYNC_IN_PROCESS; - LogPrintf("CActiveLegacyMasternodeManager::ManageState -- %s: %s\n", GetStateString(), GetStatus()); - return; - } - - if (nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) { - nState = ACTIVE_MASTERNODE_INITIAL; - } - - LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); - - if (eType == MASTERNODE_UNKNOWN) { - ManageStateInitial(connman); - } - - if (eType == MASTERNODE_REMOTE) { - ManageStateRemote(); - } - - SendMasternodePing(connman); -} - -std::string CActiveLegacyMasternodeManager::GetStateString() const -{ - switch (nState) { - case ACTIVE_MASTERNODE_INITIAL: - return "INITIAL"; - case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: - return "SYNC_IN_PROCESS"; - case ACTIVE_MASTERNODE_INPUT_TOO_NEW: - return "INPUT_TOO_NEW"; - case ACTIVE_MASTERNODE_NOT_CAPABLE: - return "NOT_CAPABLE"; - case ACTIVE_MASTERNODE_STARTED: - return "STARTED"; - default: - return "UNKNOWN"; - } -} - -std::string CActiveLegacyMasternodeManager::GetStatus() const -{ - switch (nState) { - case ACTIVE_MASTERNODE_INITIAL: - return "Node just started, not yet activated"; - case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: - return "Sync in progress. Must wait until sync is complete to start Masternode"; - case ACTIVE_MASTERNODE_INPUT_TOO_NEW: - return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations); - case ACTIVE_MASTERNODE_NOT_CAPABLE: - return "Not capable masternode: " + strNotCapableReason; - case ACTIVE_MASTERNODE_STARTED: - return "Masternode successfully started"; - default: - return "Unknown"; - } -} - -std::string CActiveLegacyMasternodeManager::GetTypeString() const -{ - std::string strType; - switch (eType) { - case MASTERNODE_REMOTE: - strType = "REMOTE"; - break; - default: - strType = "UNKNOWN"; - break; - } - return strType; -} - -bool CActiveLegacyMasternodeManager::SendMasternodePing(CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) return false; - - if (!fPingerEnabled) { - LogPrint("masternode", "CActiveLegacyMasternodeManager::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString()); - return false; - } - - if (!mnodeman.Has(activeMasternodeInfo.outpoint)) { - strNotCapableReason = "Masternode not in masternode list"; - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveLegacyMasternodeManager::SendMasternodePing -- %s: %s\n", GetStateString(), strNotCapableReason); - return false; - } - - CMasternodePing mnp(activeMasternodeInfo.outpoint); - mnp.nSentinelVersion = nSentinelVersion; - mnp.fSentinelIsCurrent = - (abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_SENTINEL_PING_MAX_SECONDS); - if (!mnp.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator)) { - LogPrintf("CActiveLegacyMasternodeManager::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n"); - return false; - } - - // Update lastPing for our masternode in Masternode list - if (mnodeman.IsMasternodePingedWithin(activeMasternodeInfo.outpoint, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) { - LogPrintf("CActiveLegacyMasternodeManager::SendMasternodePing -- Too early to send Masternode Ping\n"); - return false; - } - - mnodeman.SetMasternodeLastPing(activeMasternodeInfo.outpoint, mnp); - - LogPrintf("CActiveLegacyMasternodeManager::SendMasternodePing -- Relaying ping, collateral=%s\n", activeMasternodeInfo.outpoint.ToStringShort()); - mnp.Relay(connman); - - return true; -} - -bool CActiveLegacyMasternodeManager::UpdateSentinelPing(int version) -{ - nSentinelVersion = version; - nSentinelPingTime = GetAdjustedTime(); - - return true; -} - -void CActiveLegacyMasternodeManager::DoMaintenance(CConnman& connman) -{ - if (ShutdownRequested()) return; - - ManageState(connman); -} - -void CActiveLegacyMasternodeManager::ManageStateInitial(CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) return; - - LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); - - // Check that our local network configuration is correct - if (!fListen) { - // listen option is probably overwritten by smth else, no good - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Masternode must accept connections from outside. Make sure listen configuration option is not overwritten by some another parameter."; - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - - // First try to find whatever local address is specified by externalip option - bool fFoundLocal = GetLocal(activeMasternodeInfo.service) && CMasternode::IsValidNetAddr(activeMasternodeInfo.service); - if (!fFoundLocal) { - bool empty = true; - // If we have some peers, let's try to find our local address from one of them - connman.ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty](CNode* pnode) { - empty = false; - if (pnode->addr.IsIPv4()) - fFoundLocal = GetLocal(activeMasternodeInfo.service, &pnode->addr) && CMasternode::IsValidNetAddr(activeMasternodeInfo.service); - return !fFoundLocal; - }); - // nothing and no live connections, can't do anything for now - if (empty) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available."; - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - } - - if (!fFoundLocal && Params().NetworkIDString() == CBaseChainParams::REGTEST) { - if (Lookup("127.0.0.1", activeMasternodeInfo.service, GetListenPort(), false)) { - fFoundLocal = true; - } - } - - if (!fFoundLocal) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only."; - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - - int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort(); - if (Params().NetworkIDString() == CBaseChainParams::MAIN) { - if (activeMasternodeInfo.service.GetPort() != mainnetDefaultPort) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", activeMasternodeInfo.service.GetPort(), mainnetDefaultPort); - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - } else if (activeMasternodeInfo.service.GetPort() == mainnetDefaultPort) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", activeMasternodeInfo.service.GetPort(), mainnetDefaultPort); - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - - if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { - // Check socket connectivity - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- Checking inbound connection to '%s'\n", activeMasternodeInfo.service.ToString()); - SOCKET hSocket; - bool fConnected = ConnectSocket(activeMasternodeInfo.service, hSocket, nConnectTimeout) && IsSelectableSocket(hSocket); - CloseSocket(hSocket); - - if (!fConnected) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Could not connect to " + activeMasternodeInfo.service.ToString(); - LogPrintf("CActiveLegacyMasternodeManager::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - } - // Default to REMOTE - eType = MASTERNODE_REMOTE; - - LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled); -} - -void CActiveLegacyMasternodeManager::ManageStateRemote() -{ - if (deterministicMNManager->IsDIP3Active()) return; - - LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, keyIDOperator = %s\n", - GetStatus(), GetTypeString(), fPingerEnabled, activeMasternodeInfo.legacyKeyIDOperator.ToString()); - - mnodeman.CheckMasternode(activeMasternodeInfo.legacyKeyIDOperator, true); - masternode_info_t infoMn; - if (mnodeman.GetMasternodeInfo(activeMasternodeInfo.legacyKeyIDOperator, infoMn)) { - if (infoMn.nProtocolVersion != PROTOCOL_VERSION) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Invalid protocol version"; - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - if (activeMasternodeInfo.service != infoMn.addr) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this masternode changed recently."; - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - if (!CMasternode::IsValidStateForAutoStart(infoMn.nActiveState)) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState)); - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(infoMn.outpoint); - if (dmn) { - if (dmn->pdmnState->addr != infoMn.addr) { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = strprintf("Masternode collateral is a ProTx and ProTx address does not match local address"); - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); - return; - } - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- Collateral is a ProTx\n"); - } - if (nState != ACTIVE_MASTERNODE_STARTED) { - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- STARTED!\n"); - activeMasternodeInfo.outpoint = infoMn.outpoint; - activeMasternodeInfo.service = infoMn.addr; - fPingerEnabled = true; - nState = ACTIVE_MASTERNODE_STARTED; - } - } else { - nState = ACTIVE_MASTERNODE_NOT_CAPABLE; - strNotCapableReason = "Masternode not in masternode list"; - LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); - } + // TODO: regtest is fine with any addresses for now, + // should probably be a bit smarter if one day we start to implement tests for this + return Params().NetworkIDString() == CBaseChainParams::REGTEST || + (addrIn.IsIPv4() && IsReachable(addrIn) && addrIn.IsRoutable()); } diff --git a/src/activemasternode.h b/src/activemasternode.h index e83b4edba7..5099babae9 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -15,7 +15,6 @@ #include "evo/providertx.h" struct CActiveMasternodeInfo; -class CActiveLegacyMasternodeManager; class CActiveDeterministicMasternodeManager; static const int ACTIVE_MASTERNODE_INITIAL = 0; // initial state @@ -25,14 +24,10 @@ static const int ACTIVE_MASTERNODE_NOT_CAPABLE = 3; static const int ACTIVE_MASTERNODE_STARTED = 4; extern CActiveMasternodeInfo activeMasternodeInfo; -extern CActiveLegacyMasternodeManager legacyActiveMasternodeManager; extern CActiveDeterministicMasternodeManager* activeMasternodeManager; struct CActiveMasternodeInfo { // Keys for the active Masternode - CKeyID legacyKeyIDOperator; - CKey legacyKeyOperator; - std::unique_ptr blsPubKeyOperator; std::unique_ptr blsKeyOperator; @@ -70,60 +65,10 @@ public: std::string GetStateString() const; std::string GetStatus() const; + static bool IsValidNetAddr(CService addrIn); + private: bool GetLocalAddress(CService& addrRet); }; -// Responsible for activating the Masternode and pinging the network (legacy MN list) -class CActiveLegacyMasternodeManager -{ -public: - enum masternode_type_enum_t { - MASTERNODE_UNKNOWN = 0, - MASTERNODE_REMOTE = 1 - }; - -private: - // critical section to protect the inner data structures - mutable CCriticalSection cs; - - masternode_type_enum_t eType; - - bool fPingerEnabled; - - /// Ping Masternode - bool SendMasternodePing(CConnman& connman); - - // sentinel ping data - int64_t nSentinelPingTime; - uint32_t nSentinelVersion; - -public: - int nState; // should be one of ACTIVE_MASTERNODE_XXXX - std::string strNotCapableReason; - - - CActiveLegacyMasternodeManager() : - eType(MASTERNODE_UNKNOWN), - fPingerEnabled(false), - nState(ACTIVE_MASTERNODE_INITIAL) - { - } - - /// Manage state of active Masternode - void ManageState(CConnman& connman); - - std::string GetStateString() const; - std::string GetStatus() const; - std::string GetTypeString() const; - - bool UpdateSentinelPing(int version); - - void DoMaintenance(CConnman& connman); - -private: - void ManageStateInitial(CConnman& connman); - void ManageStateRemote(); -}; - #endif diff --git a/src/dashd.cpp b/src/dashd.cpp index 03e67d725c..af1b1cdc0e 100644 --- a/src/dashd.cpp +++ b/src/dashd.cpp @@ -16,7 +16,6 @@ #include "noui.h" #include "scheduler.h" #include "util.h" -#include "masternodeconfig.h" #include "httpserver.h" #include "httprpc.h" #include "utilstrencodings.h" @@ -125,13 +124,6 @@ bool AppInit(int argc, char* argv[]) return false; } - // parse masternode.conf - std::string strErr; - if(!masternodeConfig.read(strErr)) { - fprintf(stderr,"Error reading masternode configuration file: %s\n", strErr.c_str()); - return false; - } - // Command-line RPC bool fCommandLine = false; for (int i = 1; i < argc; i++) diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 625641d011..85751a4b86 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -56,13 +56,11 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con if (fLiteMode) return; - mnodeman.UpdatedBlockTip(pindexNew); CPrivateSend::UpdatedBlockTip(pindexNew); #ifdef ENABLE_WALLET privateSendClient.UpdatedBlockTip(pindexNew); #endif // ENABLE_WALLET instantsend.UpdatedBlockTip(pindexNew); - mnpayments.UpdatedBlockTip(pindexNew, connman); governance.UpdatedBlockTip(pindexNew, connman); } @@ -71,3 +69,10 @@ void CDSNotificationInterface::SyncTransaction(const CTransaction &tx, const CBl instantsend.SyncTransaction(tx, pindex, posInBlock); CPrivateSend::SyncTransaction(tx, pindex, posInBlock); } + +void CDSNotificationInterface::NotifyMasternodeListChanged(const CDeterministicMNList& newList) +{ + governance.CheckMasternodeOrphanObjects(connman); + governance.CheckMasternodeOrphanVotes(connman); + governance.UpdateCachesAndClean(); +} diff --git a/src/dsnotificationinterface.h b/src/dsnotificationinterface.h index 8e7df34a33..d800289d12 100644 --- a/src/dsnotificationinterface.h +++ b/src/dsnotificationinterface.h @@ -22,6 +22,7 @@ protected: void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) override; void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) override; + void NotifyMasternodeListChanged(const CDeterministicMNList& newList) override; private: CConnman& connman; diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 0f79db6667..61c322124f 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -473,6 +473,10 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde __func__, nHeight, newList.GetAllMNsCount()); } + if (!diff.addedMNs.empty() || !diff.removedMns.empty()) { + GetMainSignals().NotifyMasternodeListChanged(newList); + } + const auto& consensusParams = Params().GetConsensus(); if (nHeight == consensusParams.DIP0003Height) { if (!consensusParams.DIP0003Hash.IsNull() && consensusParams.DIP0003Hash != pindex->GetBlockHash()) { @@ -495,10 +499,18 @@ bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex* int nHeight = pindex->nHeight; uint256 blockHash = block.GetHash(); + CDeterministicMNListDiff diff; + evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHash), diff); + evoDb.Erase(std::make_pair(DB_LIST_DIFF, blockHash)); evoDb.Erase(std::make_pair(DB_LIST_SNAPSHOT, blockHash)); mnListsCache.erase(blockHash); + if (!diff.addedMNs.empty() || !diff.removedMns.empty()) { + auto prevList = GetListForBlock(pindex->pprev->GetBlockHash()); + GetMainSignals().NotifyMasternodeListChanged(prevList); + } + const auto& consensusParams = Params().GetConsensus(); if (nHeight == consensusParams.DIP0003Height) { LogPrintf("CDeterministicMNManager::%s -- DIP3 is not active anymore. nHeight=%d\n", __func__, nHeight); diff --git a/src/governance-object.cpp b/src/governance-object.cpp index d8694ee20e..1adee75523 100644 --- a/src/governance-object.cpp +++ b/src/governance-object.cpp @@ -312,70 +312,6 @@ void CGovernanceObject::SetMasternodeOutpoint(const COutPoint& outpoint) masternodeOutpoint = outpoint; } -bool CGovernanceObject::Sign(const CKey& key, const CKeyID& keyID) -{ - std::string strError; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::SignHash(hash, key, vchSig)) { - LogPrintf("CGovernanceObject::Sign -- SignHash() failed\n"); - return false; - } - - if (!CHashSigner::VerifyHash(hash, keyID, vchSig, strError)) { - LogPrintf("CGovernanceObject::Sign -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = GetSignatureMessage(); - if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) { - LogPrintf("CGovernanceObject::Sign -- SignMessage() failed\n"); - return false; - } - - if (!CMessageSigner::VerifyMessage(keyID, vchSig, strMessage, strError)) { - LogPrintf("CGovernanceObject::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } - - LogPrint("gobject", "CGovernanceObject::Sign -- pubkey id = %s, masternode = %s\n", - keyID.ToString(), masternodeOutpoint.ToStringShort()); - - return true; -} - -bool CGovernanceObject::CheckSignature(const CKeyID& keyID) const -{ - std::string strError; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, keyID, vchSig, strError)) { - // could be an old object - std::string strMessage = GetSignatureMessage(); - - if (!CMessageSigner::VerifyMessage(keyID, vchSig, strMessage, strError)) { - // nope, not in old format either - LogPrintf("CGovernance::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } - } else { - std::string strMessage = GetSignatureMessage(); - - if (!CMessageSigner::VerifyMessage(keyID, vchSig, strMessage, strError)) { - LogPrintf("CGovernance::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } - - return true; -} - bool CGovernanceObject::Sign(const CBLSSecretKey& key) { CBLSSignature sig = key.Sign(GetSignatureHash()); @@ -556,21 +492,17 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast auto mnList = deterministicMNManager->GetListAtChainTip(); std::string strOutpoint = masternodeOutpoint.ToStringShort(); - auto dmn = mnList.GetValidMNByCollateral(masternodeOutpoint); + auto dmn = mnList.GetMNByCollateral(masternodeOutpoint); if (!dmn) { - CMasternode::CollateralStatus err = CMasternode::CheckCollateral(masternodeOutpoint, CKeyID()); - if (err == CMasternode::COLLATERAL_UTXO_NOT_FOUND) { - strError = "Failed to find Masternode UTXO, missing masternode=" + strOutpoint + "\n"; - } else if (err == CMasternode::COLLATERAL_INVALID_AMOUNT) { - strError = "Masternode UTXO should have 1000 DASH, missing masternode=" + strOutpoint + "\n"; - } else if (err == CMasternode::COLLATERAL_INVALID_PUBKEY) { - fMissingMasternode = true; - strError = "Masternode not found: " + strOutpoint; - } else if (err == CMasternode::COLLATERAL_OK) { - // this should never happen with CPubKey() as a param - strError = "CheckCollateral critical failure! Masternode: " + strOutpoint; + strError = "Failed to find Masternode by UTXO, missing masternode=" + strOutpoint + "\n"; + return false; + } + if (!mnList.IsMNValid(dmn)) { + if (mnList.IsMNPoSeBanned(dmn)) { + strError = "Masternode is POSE_BANNED, masternode=" + strOutpoint + "\n"; + } else { + strError = "Masternode is invalid for unknown reason, masternode=" + strOutpoint + "\n"; } - return false; } @@ -835,41 +767,3 @@ void CGovernanceObject::CheckOrphanVotes(CConnman& connman) } } } - -std::vector CGovernanceObject::RemoveOldVotes(unsigned int nMinTime) -{ - LOCK(cs); - - // Drop pre-DIP3 votes from vote db - auto removed = fileVotes.RemoveOldVotes(nMinTime); - - if (!removed.empty()) { - std::string removedStr; - for (auto& h : removed) { - removedStr += strprintf(" %s\n", h.ToString()); - } - LogPrintf("CGovernanceObject::RemoveOldVotes -- Removed %d old (pre-DIP3) votes for %s:\n%s\n", removed.size(), GetHash().ToString(), removedStr); - fDirtyCache = true; - } - - // Same for current votes per MN for this specific object - auto itMnPair = mapCurrentMNVotes.begin(); - while (itMnPair != mapCurrentMNVotes.end()) { - auto& miRef = itMnPair->second.mapInstances; - auto itVotePair = miRef.begin(); - while (itVotePair != miRef.end()) { - if (itVotePair->second.nCreationTime < nMinTime) { - miRef.erase(itVotePair++); - } else { - ++itVotePair; - } - } - if (miRef.empty()) { - mapCurrentMNVotes.erase(itMnPair++); - } else { - ++itMnPair; - } - } - - return removed; -} diff --git a/src/governance-object.h b/src/governance-object.h index ae3f55321a..a51c66a864 100644 --- a/src/governance-object.h +++ b/src/governance-object.h @@ -259,8 +259,6 @@ public: // Signature related functions void SetMasternodeOutpoint(const COutPoint& outpoint); - bool Sign(const CKey& key, const CKeyID& keyID); - bool CheckSignature(const CKeyID& keyID) const; bool Sign(const CBLSSecretKey& key); bool CheckSignature(const CBLSPublicKey& pubKey) const; @@ -354,9 +352,6 @@ private: std::set RemoveInvalidProposalVotes(const COutPoint& mnOutpoint); void CheckOrphanVotes(CConnman& connman); - - // TODO can be removed after DIP3 is fully deployed - std::vector RemoveOldVotes(unsigned int nMinTime); }; diff --git a/src/governance.cpp b/src/governance.cpp index 665f37debb..f428fc8309 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -144,7 +144,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, const std::string& strComm return; } - if (!masternodeSync.IsMasternodeListSynced()) { + if (!masternodeSync.IsBlockchainSynced()) { LogPrint("gobject", "MNGOVERNANCEOBJECT -- masternode list not synced\n"); return; } @@ -222,12 +222,6 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, const std::string& strComm CGovernanceVote vote; vRecv >> vote; - // TODO remove this check after full DIP3 deployment - if (vote.GetTimestamp() < GetMinVoteTime()) { - // Ignore votes pre-DIP3 - return; - } - uint256 nHash = vote.GetHash(); { @@ -241,7 +235,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, const std::string& strComm } // Ignore such messages until masternode list is synced - if (!masternodeSync.IsMasternodeListSynced()) { + if (!masternodeSync.IsBlockchainSynced()) { LogPrint("gobject", "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n"); return; } @@ -585,7 +579,6 @@ void CGovernanceManager::DoMaintenance(CConnman& connman) if (fLiteMode || !masternodeSync.IsSynced() || ShutdownRequested()) return; if (deterministicMNManager->IsDIP3Active()) { - ClearPreDIP3Votes(); RemoveInvalidProposalVotes(); } @@ -603,7 +596,7 @@ void CGovernanceManager::DoMaintenance(CConnman& connman) bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) { // do not request objects until it's time to sync - if (!masternodeSync.IsWinnersListSynced()) return false; + if (!masternodeSync.IsBlockchainSynced()) return false; LOCK(cs); @@ -1308,7 +1301,6 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex, CConnman& co LogPrint("gobject", "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); if (deterministicMNManager->IsDIP3Active(pindex->nHeight)) { - ClearPreDIP3Votes(); RemoveInvalidProposalVotes(); } @@ -1401,38 +1393,3 @@ void CGovernanceManager::RemoveInvalidProposalVotes() // store current MN list for the next run so that we can determine which keys changed lastMNListForVotingKeys = curMNList; } - - -unsigned int CGovernanceManager::GetMinVoteTime() -{ - LOCK(cs_main); - if (!deterministicMNManager->IsDIP3Active()) { - return 0; - } - int64_t dip3SporkHeight = Params().GetConsensus().DIP0003Height; - return chainActive[dip3SporkHeight]->nTime; -} - -void CGovernanceManager::ClearPreDIP3Votes() -{ - // This removes all votes which were created before DIP3 spork15 activation - // All these votes are invalid immediately after spork15 activation due to the introduction of voting keys, which - // are not equal to the old masternode private keys - - unsigned int minVoteTime = GetMinVoteTime(); - - LOCK(cs); - for (auto& p : mapObjects) { - auto& obj = p.second; - auto removed = obj.RemoveOldVotes(minVoteTime); - if (removed.empty()) { - continue; - } - for (auto& voteHash : removed) { - cmapVoteToObject.Erase(voteHash); - cmapInvalidVotes.Erase(voteHash); - cmmapOrphanVotes.Erase(voteHash); - setRequestedVotes.erase(voteHash); - } - } -} diff --git a/src/governance.h b/src/governance.h index 6571347795..7fd20e08bb 100644 --- a/src/governance.h +++ b/src/governance.h @@ -457,9 +457,6 @@ private: void RemoveInvalidProposalVotes(); - // TODO can be removed after full DIP3 deployment - unsigned int GetMinVoteTime(); - void ClearPreDIP3Votes(); }; #endif diff --git a/src/init.cpp b/src/init.cpp index c94451be40..1cda57b89e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -56,7 +56,6 @@ #include "masternode-payments.h" #include "masternode-sync.h" #include "masternodeman.h" -#include "masternodeconfig.h" #include "messagesigner.h" #include "netfulfilledman.h" #ifdef ENABLE_WALLET @@ -262,8 +261,6 @@ void PrepareShutdown() // STORE DATA CACHES INTO SERIALIZED DAT FILES CFlatDB flatdb1("mncache.dat", "magicMasternodeCache"); flatdb1.Dump(mnodeman); - CFlatDB flatdb2("mnpayments.dat", "magicMasternodePaymentsCache"); - flatdb2.Dump(mnpayments); CFlatDB flatdb3("governance.dat", "magicGovernanceCache"); flatdb3.Dump(governance); CFlatDB flatdb4("netfulfilled.dat", "magicFulfilledCache"); @@ -589,9 +586,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Masternode options:")); strUsage += HelpMessageOpt("-masternode=", strprintf(_("Enable the client to act as a masternode (0-1, default: %u)"), 0)); - strUsage += HelpMessageOpt("-mnconf=", strprintf(_("Specify masternode configuration file (default: %s)"), "masternode.conf")); - strUsage += HelpMessageOpt("-mnconflock=", strprintf(_("Lock masternodes from masternode configuration file (default: %u)"), 1)); - strUsage += HelpMessageOpt("-masternodeprivkey=", _("Set the masternode private key")); strUsage += HelpMessageOpt("-masternodeblsprivkey=", _("Set the masternode BLS private key")); #ifdef ENABLE_WALLET @@ -1937,19 +1931,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) if(fMasternodeMode) { LogPrintf("MASTERNODE:\n"); - std::string strMasterNodePrivKey = GetArg("-masternodeprivkey", ""); - if(!strMasterNodePrivKey.empty()) { - CPubKey pubKeyMasternode; - if(!CMessageSigner::GetKeysFromSecret(strMasterNodePrivKey, activeMasternodeInfo.legacyKeyOperator, pubKeyMasternode)) - return InitError(_("Invalid masternodeprivkey. Please see documenation.")); - - activeMasternodeInfo.legacyKeyIDOperator = pubKeyMasternode.GetID(); - - LogPrintf(" keyIDOperator: %s\n", CBitcoinAddress(activeMasternodeInfo.legacyKeyIDOperator).ToString()); - } else { - //return InitError(_("You must specify a masternodeprivkey in the configuration. Please see documentation for help.")); - } - std::string strMasterNodeBLSPrivKey = GetArg("-masternodeblsprivkey", ""); if(!strMasterNodeBLSPrivKey.empty()) { auto binKey = ParseHex(strMasterNodeBLSPrivKey); @@ -1979,27 +1960,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) } #ifdef ENABLE_WALLET - LogPrintf("Using masternode config file %s\n", GetMasternodeConfigFile().string()); - - if(GetBoolArg("-mnconflock", true) && pwalletMain && (masternodeConfig.getCount() > 0)) { - LOCK(pwalletMain->cs_wallet); - LogPrintf("Locking Masternodes:\n"); - uint256 mnTxHash; - uint32_t outputIndex; - for (const auto& mne : masternodeConfig.getEntries()) { - mnTxHash.SetHex(mne.getTxHash()); - outputIndex = (uint32_t)atoi(mne.getOutputIndex()); - COutPoint outpoint = COutPoint(mnTxHash, outputIndex); - // don't lock non-spendable outpoint (i.e. it's already spent or it's not from this wallet at all) - if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) { - LogPrintf(" %s %s - IS NOT SPENDABLE, was not locked\n", mne.getTxHash(), mne.getOutputIndex()); - continue; - } - pwalletMain->LockCoin(outpoint); - LogPrintf(" %s %s - locked successfully\n", mne.getTxHash(), mne.getOutputIndex()); - } - } - // ********************************************************* Step 11b: setup PrivateSend privateSendClient.nLiquidityProvider = std::min(std::max((int)GetArg("-liquidityprovider", DEFAULT_PRIVATESEND_LIQUIDITY), MIN_PRIVATESEND_LIQUIDITY), MAX_PRIVATESEND_LIQUIDITY); @@ -2042,24 +2002,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("Failed to load masternode cache from") + "\n" + (pathDB / strDBName).string()); } - if(mnodeman.size()) { - strDBName = "mnpayments.dat"; - uiInterface.InitMessage(_("Loading masternode payment cache...")); - CFlatDB flatdb2(strDBName, "magicMasternodePaymentsCache"); - if(!flatdb2.Load(mnpayments)) { - return InitError(_("Failed to load masternode payments cache from") + "\n" + (pathDB / strDBName).string()); - } - - strDBName = "governance.dat"; - uiInterface.InitMessage(_("Loading governance cache...")); - CFlatDB flatdb3(strDBName, "magicGovernanceCache"); - if(!flatdb3.Load(governance)) { - return InitError(_("Failed to load governance cache from") + "\n" + (pathDB / strDBName).string()); - } - governance.InitOnLoad(); - } else { - uiInterface.InitMessage(_("Masternode cache is empty, skipping payments and governance cache...")); + strDBName = "governance.dat"; + uiInterface.InitMessage(_("Loading governance cache...")); + CFlatDB flatdb3(strDBName, "magicGovernanceCache"); + if(!flatdb3.Load(governance)) { + return InitError(_("Failed to load governance cache from") + "\n" + (pathDB / strDBName).string()); } + governance.InitOnLoad(); strDBName = "netfulfilled.dat"; uiInterface.InitMessage(_("Loading fulfilled requests cache...")); @@ -2085,9 +2034,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) scheduler.scheduleEvery(boost::bind(&CNetFulfilledRequestManager::DoMaintenance, boost::ref(netfulfilledman)), 60); scheduler.scheduleEvery(boost::bind(&CMasternodeSync::DoMaintenance, boost::ref(masternodeSync), boost::ref(*g_connman)), 1); scheduler.scheduleEvery(boost::bind(&CMasternodeMan::DoMaintenance, boost::ref(mnodeman), boost::ref(*g_connman)), 1); - scheduler.scheduleEvery(boost::bind(&CActiveLegacyMasternodeManager::DoMaintenance, boost::ref(legacyActiveMasternodeManager), boost::ref(*g_connman)), MASTERNODE_MIN_MNP_SECONDS); - scheduler.scheduleEvery(boost::bind(&CMasternodePayments::DoMaintenance, boost::ref(mnpayments)), 60); scheduler.scheduleEvery(boost::bind(&CGovernanceManager::DoMaintenance, boost::ref(governance), boost::ref(*g_connman)), 60 * 5); scheduler.scheduleEvery(boost::bind(&CInstantSend::DoMaintenance, boost::ref(instantsend)), 60); diff --git a/src/instantx.cpp b/src/instantx.cpp index 408d3dbccf..e33de9d764 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -79,8 +79,8 @@ void CInstantSend::ProcessMessage(CNode* pfrom, const std::string& strCommand, C connman.RemoveAskFor(nVoteHash); } - // Ignore any InstantSend messages until masternode list is synced - if (!masternodeSync.IsMasternodeListSynced()) return; + // Ignore any InstantSend messages until blockchain is synced + if (!masternodeSync.IsBlockchainSynced()) return; { LOCK(cs_instantsend); @@ -249,10 +249,6 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) LogPrint("instantsend", "CInstantSend::Vote -- Can't calculate rank for masternode %s\n", activeMasternodeInfo.outpoint.ToStringShort()); continue; } - if (!deterministicMNManager->IsDIP3Active()) { - // not used until spork15 activation - quorumModifierHash = uint256(); - } int nSignaturesTotal = COutPointLock::SIGNATURES_TOTAL; if (nRank > nSignaturesTotal) { @@ -666,7 +662,7 @@ int64_t CInstantSend::GetAverageMasternodeOrphanVoteTime() void CInstantSend::CheckAndRemove() { - if (!masternodeSync.IsMasternodeListSynced()) return; + if (!masternodeSync.IsBlockchainSynced()) return; LOCK(cs_instantsend); @@ -1033,7 +1029,6 @@ bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const if (!mnList.HasValidMNByCollateral(outpointMasternode)) { LogPrint("instantsend", "CTxLockVote::IsValid -- Unknown masternode %s\n", outpointMasternode.ToStringShort()); - mnodeman.AskForMN(pnode, outpointMasternode, connman); return false; } @@ -1071,8 +1066,8 @@ bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const LogPrint("instantsend", "CTxLockVote::IsValid -- invalid quorumModifierHash %s, expected %s\n", quorumModifierHash.ToString(), expectedQuorumModifierHash.ToString()); return false; } - } else if (deterministicMNManager->IsDIP3Active()) { - LogPrint("instantsend", "CTxLockVote::IsValid -- missing quorumModifierHash while DIP3 is active\n"); + } else { + LogPrint("instantsend", "CTxLockVote::IsValid -- missing quorumModifierHash\n"); return false; } diff --git a/src/instantx.h b/src/instantx.h index 633901adc4..dccdb52e97 100644 --- a/src/instantx.h +++ b/src/instantx.h @@ -233,7 +233,7 @@ class CTxLockVote private: uint256 txHash; COutPoint outpoint; - // TODO remove this member when the legacy masternode code is removed after DIP3 deployment + // TODO remove this member (not needed anymore after DIP3 has been deployed) COutPoint outpointMasternode; uint256 quorumModifierHash; uint256 masternodeProTxHash; @@ -272,12 +272,8 @@ public: READWRITE(txHash); READWRITE(outpoint); READWRITE(outpointMasternode); - if (deterministicMNManager->IsDIP3Active()) { - // Starting with spork15 activation, the proTxHash and quorumModifierHash is included. When we bump to >= 70214, we can remove - // the surrounding if. We might also remove outpointMasternode as well later - READWRITE(quorumModifierHash); - READWRITE(masternodeProTxHash); - } + READWRITE(quorumModifierHash); + READWRITE(masternodeProTxHash); if (!(s.GetType() & SER_GETHASH)) { READWRITE(vchMasternodeSignature); } diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index bbab429894..27d2ee7f5e 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -19,13 +19,8 @@ #include -/** Object for who's going to get paid on which blocks */ CMasternodePayments mnpayments; -CCriticalSection cs_vecPayees; -CCriticalSection cs_mapMasternodeBlocks; -CCriticalSection cs_mapMasternodePaymentVotes; - bool IsOldBudgetBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string& strErrorRet) { const Consensus::Params& consensusParams = Params().GetConsensus(); bool isBlockRewardValueMet = (block.vtx[0]->GetValueOut() <= blockReward); @@ -167,7 +162,7 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) { - if(!masternodeSync.IsSynced() || fLiteMode) { + if(fLiteMode) { //there is no budget data to use to check anything, let's just accept the longest chain if(fDebug) LogPrintf("%s -- WARNING: Not enough data, skipping block payee checks\n", __func__); return true; @@ -193,9 +188,6 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc if(CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) { if(CSuperblockManager::IsValid(txNew, nBlockHeight, blockReward)) { LogPrint("gobject", "%s -- Valid superblock at height %d: %s", __func__, nBlockHeight, txNew.ToString()); - // only allow superblock and masternode payments in the same block after spork15 activation - if (!deterministicMNManager->IsDIP3Active(nBlockHeight)) - return true; // continue validation, should also pay MN } else { LogPrintf("%s -- ERROR: Invalid superblock detected at height %d: %s", __func__, nBlockHeight, txNew.ToString()); @@ -210,25 +202,14 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc LogPrint("gobject", "%s -- Superblocks are disabled, no superblocks allowed\n", __func__); } - // If this isn't a superblock or spork15 is activated, check for correct masternode payment + // Check for correct masternode payment if(mnpayments.IsTransactionValid(txNew, nBlockHeight, blockReward)) { LogPrint("mnpayments", "%s -- Valid masternode payment at height %d: %s", __func__, nBlockHeight, txNew.ToString()); return true; } - if (deterministicMNManager->IsDIP3Active(nBlockHeight)) { - // always enforce masternode payments when spork15 is active - LogPrintf("%s -- ERROR: Invalid masternode payment detected at height %d: %s", __func__, nBlockHeight, txNew.ToString()); - return false; - } else { - if(sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { - LogPrintf("%s -- ERROR: Invalid masternode payment detected at height %d: %s", __func__, nBlockHeight, txNew.ToString()); - return false; - } - - LogPrintf("%s-- WARNING: Masternode payment enforcement is disabled, accepting any payee\n", __func__); - return true; - } + LogPrintf("%s -- ERROR: Invalid masternode payment detected at height %d: %s", __func__, nBlockHeight, txNew.ToString()); + return false; } void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, std::vector& voutMasternodePaymentsRet, std::vector& voutSuperblockPaymentsRet) @@ -241,14 +222,6 @@ void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blo CSuperblockManager::GetSuperblockPayments(nBlockHeight, voutSuperblockPaymentsRet); } - bool allowSuperblockAndMNReward = deterministicMNManager->IsDIP3Active(nBlockHeight); - - // don't allow payments to superblocks AND masternodes before spork15 activation - if (!voutSuperblockPaymentsRet.empty() && !allowSuperblockAndMNReward) { - txNew.vout.insert(txNew.vout.end(), voutSuperblockPaymentsRet.begin(), voutSuperblockPaymentsRet.end()); - return; - } - if (!mnpayments.GetMasternodeTxOuts(nBlockHeight, blockReward, voutMasternodePaymentsRet)) { LogPrint("mnpayments", "%s -- no masternode to pay (MN list probably empty)\n", __func__); } @@ -269,17 +242,6 @@ void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blo nBlockHeight, blockReward, voutMasternodeStr, txNew.ToString()); } -std::string GetLegacyRequiredPaymentsString(int nBlockHeight) -{ - // IF WE HAVE A ACTIVATED TRIGGER FOR THIS HEIGHT - IT IS A SUPERBLOCK, GET THE REQUIRED PAYEES - if(CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) { - return CSuperblockManager::GetRequiredPaymentsString(nBlockHeight); - } - - // OTHERWISE, PAY MASTERNODE - return mnpayments.GetRequiredPaymentsString(nBlockHeight); -} - std::string GetRequiredPaymentsString(int nBlockHeight, const CDeterministicMNCPtr &payee) { std::string strPayee = "Unknown"; @@ -304,16 +266,12 @@ std::map GetRequiredPaymentsStrings(int nStartHeight, int nEnd bool doProjection = false; for(int h = nStartHeight; h < nEndHeight; h++) { - if (deterministicMNManager->IsDIP3Active(h)) { - if (h <= nChainTipHeight) { - auto payee = deterministicMNManager->GetListForBlock(chainActive[h - 1]->GetBlockHash()).GetMNPayee(); - mapPayments.emplace(h, GetRequiredPaymentsString(h, payee)); - } else { - doProjection = true; - break; - } + if (h <= nChainTipHeight) { + auto payee = deterministicMNManager->GetListForBlock(chainActive[h - 1]->GetBlockHash()).GetMNPayee(); + mapPayments.emplace(h, GetRequiredPaymentsString(h, payee)); } else { - mapPayments.emplace(h, GetLegacyRequiredPaymentsString(h)); + doProjection = true; + break; } } if (doProjection) { @@ -328,33 +286,6 @@ std::map GetRequiredPaymentsStrings(int nStartHeight, int nEnd return mapPayments; } -void CMasternodePayments::Clear() -{ - LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePaymentVotes); - mapMasternodeBlocks.clear(); - mapMasternodePaymentVotes.clear(); -} - -bool CMasternodePayments::UpdateLastVote(const CMasternodePaymentVote& vote) -{ - if (deterministicMNManager->IsDIP3Active()) - return false; - - LOCK(cs_mapMasternodePaymentVotes); - - const auto it = mapMasternodesLastVote.find(vote.masternodeOutpoint); - if (it != mapMasternodesLastVote.end()) { - if (it->second == vote.nBlockHeight) - return false; - it->second = vote.nBlockHeight; - return true; - } - - //record this masternode voted - mapMasternodesLastVote.emplace(vote.masternodeOutpoint, vote.nBlockHeight); - return true; -} - /** * GetMasternodeTxOuts * @@ -367,23 +298,8 @@ bool CMasternodePayments::GetMasternodeTxOuts(int nBlockHeight, CAmount blockRew voutMasternodePaymentsRet.clear(); if(!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePaymentsRet)) { - if (deterministicMNManager->IsDIP3Active(nBlockHeight)) { - LogPrintf("CMasternodePayments::%s -- deterministic masternode lists enabled and no payee\n", __func__); - return false; - } - - // no masternode detected... - int nCount = 0; - masternode_info_t mnInfo; - if(!mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount, mnInfo)) { - // ...and we can't calculate it on our own - LogPrintf("CMasternodePayments::%s -- Failed to detect masternode to pay\n", __func__); - return false; - } - // fill payee with locally calculated winner and hope for the best - CScript payee = GetScriptForDestination(mnInfo.keyIDCollateralAddress); - CAmount masternodePayment = GetMasternodePayment(nBlockHeight, blockReward); - voutMasternodePaymentsRet.emplace_back(masternodePayment, payee); + LogPrintf("CMasternodePayments::%s -- no payee (deterministic masternode list empty)\n", __func__); + return false; } for (const auto& txout : voutMasternodePaymentsRet) { @@ -397,254 +313,45 @@ bool CMasternodePayments::GetMasternodeTxOuts(int nBlockHeight, CAmount blockRew return true; } -int CMasternodePayments::GetMinMasternodePaymentsProto() const { - return sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES) - ? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 - : MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1; -} - -void CMasternodePayments::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) - return; - - if(fLiteMode) return; // disable all Dash specific functionality - - if (strCommand == NetMsgType::MASTERNODEPAYMENTSYNC) { //Masternode Payments Request Sync - - if(pfrom->nVersion < GetMinMasternodePaymentsProto()) { - LogPrint("mnpayments", "MASTERNODEPAYMENTSYNC -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); - connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", GetMinMasternodePaymentsProto()))); - return; - } - - // Ignore such requests until we are fully synced. - // We could start processing this after masternode list is synced - // but this is a heavy one so it's better to finish sync first. - if (!masternodeSync.IsSynced()) return; - - if(netfulfilledman.HasFulfilledRequest(pfrom->addr, NetMsgType::MASTERNODEPAYMENTSYNC)) { - LOCK(cs_main); - // Asking for the payments list multiple times in a short period of time is no good - LogPrintf("MASTERNODEPAYMENTSYNC -- peer already asked me for the list, peer=%d\n", pfrom->id); - Misbehaving(pfrom->GetId(), 20); - return; - } - netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::MASTERNODEPAYMENTSYNC); - - Sync(pfrom, connman); - LogPrintf("MASTERNODEPAYMENTSYNC -- Sent Masternode payment votes to peer=%d\n", pfrom->id); - - } else if (strCommand == NetMsgType::MASTERNODEPAYMENTVOTE) { // Masternode Payments Vote for the Winner - - CMasternodePaymentVote vote; - vRecv >> vote; - - if(pfrom->nVersion < GetMinMasternodePaymentsProto()) { - LogPrint("mnpayments", "MASTERNODEPAYMENTVOTE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); - connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", GetMinMasternodePaymentsProto()))); - return; - } - - uint256 nHash = vote.GetHash(); - - { - LOCK(cs_main); - connman.RemoveAskFor(nHash); - } - - // TODO: clear setAskFor for MSG_MASTERNODE_PAYMENT_BLOCK too - - // Ignore any payments messages until masternode list is synced - if(!masternodeSync.IsMasternodeListSynced()) return; - - { - LOCK(cs_mapMasternodePaymentVotes); - - auto res = mapMasternodePaymentVotes.emplace(nHash, vote); - - // Avoid processing same vote multiple times if it was already verified earlier - if(!res.second && res.first->second.IsVerified()) { - LogPrint("mnpayments", "MASTERNODEPAYMENTVOTE -- hash=%s, nBlockHeight=%d/%d seen\n", - nHash.ToString(), vote.nBlockHeight, nCachedBlockHeight); - return; - } - - // Mark vote as non-verified when it's seen for the first time, - // AddOrUpdatePaymentVote() below should take care of it if vote is actually ok - res.first->second.MarkAsNotVerified(); - } - - int nFirstBlock = nCachedBlockHeight - GetStorageLimit(); - if(vote.nBlockHeight < nFirstBlock || vote.nBlockHeight > nCachedBlockHeight+20) { - LogPrint("mnpayments", "MASTERNODEPAYMENTVOTE -- vote out of range: nFirstBlock=%d, nBlockHeight=%d, nHeight=%d\n", nFirstBlock, vote.nBlockHeight, nCachedBlockHeight); - return; - } - - std::string strError = ""; - if(!vote.IsValid(pfrom, nCachedBlockHeight, strError, connman)) { - LogPrint("mnpayments", "MASTERNODEPAYMENTVOTE -- invalid message, error: %s\n", strError); - return; - } - - masternode_info_t mnInfo; - if(!mnodeman.GetMasternodeInfo(vote.masternodeOutpoint, mnInfo)) { - // mn was not found, so we can't check vote, some info is probably missing - LogPrintf("MASTERNODEPAYMENTVOTE -- masternode is missing %s\n", vote.masternodeOutpoint.ToStringShort()); - mnodeman.AskForMN(pfrom, vote.masternodeOutpoint, connman); - return; - } - - int nDos = 0; - if(!vote.CheckSignature(mnInfo.legacyKeyIDOperator, nCachedBlockHeight, nDos)) { - if(nDos) { - LOCK(cs_main); - LogPrintf("MASTERNODEPAYMENTVOTE -- ERROR: invalid signature\n"); - Misbehaving(pfrom->GetId(), nDos); - } else { - // only warn about anything non-critical (i.e. nDos == 0) in debug mode - LogPrint("mnpayments", "MASTERNODEPAYMENTVOTE -- WARNING: invalid signature\n"); - } - // Either our info or vote info could be outdated. - // In case our info is outdated, ask for an update, - mnodeman.AskForMN(pfrom, vote.masternodeOutpoint, connman); - // but there is nothing we can do if vote info itself is outdated - // (i.e. it was signed by a mn which changed its key), - // so just quit here. - return; - } - - if(!UpdateLastVote(vote)) { - LogPrintf("MASTERNODEPAYMENTVOTE -- masternode already voted, masternode=%s\n", vote.masternodeOutpoint.ToStringShort()); - return; - } - - CTxDestination address1; - ExtractDestination(vote.payee, address1); - CBitcoinAddress address2(address1); - - LogPrint("mnpayments", "MASTERNODEPAYMENTVOTE -- vote: address=%s, nBlockHeight=%d, nHeight=%d, prevout=%s, hash=%s new\n", - address2.ToString(), vote.nBlockHeight, nCachedBlockHeight, vote.masternodeOutpoint.ToStringShort(), nHash.ToString()); - - if(AddOrUpdatePaymentVote(vote)){ - vote.Relay(connman); - masternodeSync.BumpAssetLastTime("MASTERNODEPAYMENTVOTE"); - } - } -} - -uint256 CMasternodePaymentVote::GetHash() const -{ - // Note: doesn't match serialization - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << *(CScriptBase*)(&payee); - ss << nBlockHeight; - ss << masternodeOutpoint; - return ss.GetHash(); -} - -uint256 CMasternodePaymentVote::GetSignatureHash() const -{ - return SerializeHash(*this); -} - -bool CMasternodePaymentVote::Sign() -{ - std::string strError; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if(!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) { - LogPrintf("CMasternodePaymentVote::%s -- SignHash() failed\n", __func__); - return false; - } - - if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) { - LogPrintf("CMasternodePaymentVote::%s -- VerifyHash() failed, error: %s\n", __func__, strError); - return false; - } - } else { - std::string strMessage = masternodeOutpoint.ToStringShort() + - std::to_string(nBlockHeight) + - ScriptToAsmStr(payee); - - if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) { - LogPrintf("CMasternodePaymentVote::%s -- SignMessage() failed\n", __func__); - return false; - } - - if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CMasternodePaymentVote::%s -- VerifyMessage() failed, error: %s\n", __func__, strError); - return false; - } - } - - return true; -} - bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward, std::vector& voutMasternodePaymentsRet) const { voutMasternodePaymentsRet.clear(); CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward); - if (deterministicMNManager->IsDIP3Active(nBlockHeight)) { - uint256 blockHash; - { - LOCK(cs_main); - if (nBlockHeight - 1 > chainActive.Height()) { - // there are some cases (e.g. IsScheduled) where legacy/compatibility code runs into this method with - // block heights above the chain tip. Return false in this case - // TODO remove this when removing the compatibility code and make sure this method is only called with - // correct block height - return false; - } - blockHash = chainActive[nBlockHeight - 1]->GetBlockHash(); - } - uint256 proTxHash; - auto dmnPayee = deterministicMNManager->GetListForBlock(blockHash).GetMNPayee(); - if (!dmnPayee) { - return false; - } - - CAmount operatorReward = 0; - if (dmnPayee->nOperatorReward != 0 && dmnPayee->pdmnState->scriptOperatorPayout != CScript()) { - // This calculation might eventually turn out to result in 0 even if an operator reward percentage is given. - // This will however only happen in a few years when the block rewards drops very low. - operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000; - masternodeReward -= operatorReward; - } - - if (masternodeReward > 0) { - voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout); - } - if (operatorReward > 0) { - voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout); - } - - return true; - } else { - LOCK(cs_mapMasternodeBlocks); - auto it = mapMasternodeBlocks.find(nBlockHeight); - CScript payee; - if (it == mapMasternodeBlocks.end() || !it->second.GetBestPayee(payee)) { - return false; - } - voutMasternodePaymentsRet.emplace_back(masternodeReward, payee); - return true; + uint256 blockHash; + { + LOCK(cs_main); + blockHash = chainActive[nBlockHeight - 1]->GetBlockHash(); } + uint256 proTxHash; + auto dmnPayee = deterministicMNManager->GetListForBlock(blockHash).GetMNPayee(); + if (!dmnPayee) { + return false; + } + + CAmount operatorReward = 0; + if (dmnPayee->nOperatorReward != 0 && dmnPayee->pdmnState->scriptOperatorPayout != CScript()) { + // This calculation might eventually turn out to result in 0 even if an operator reward percentage is given. + // This will however only happen in a few years when the block rewards drops very low. + operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000; + masternodeReward -= operatorReward; + } + + if (masternodeReward > 0) { + voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout); + } + if (operatorReward > 0) { + voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout); + } + + return true; } // Is this masternode scheduled to get paid soon? // -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 blocks of votes bool CMasternodePayments::IsScheduled(const CDeterministicMNCPtr& dmnIn, int nNotBlockHeight) const { - LOCK(cs_mapMasternodeBlocks); - auto projectedPayees = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(8); for (const auto &dmn : projectedPayees) { if (dmn->proTxHash == dmnIn->proTxHash) { @@ -654,640 +361,34 @@ bool CMasternodePayments::IsScheduled(const CDeterministicMNCPtr& dmnIn, int nNo return false; } -bool CMasternodePayments::AddOrUpdatePaymentVote(const CMasternodePaymentVote& vote) -{ - uint256 blockHash = uint256(); - if(!GetBlockHash(blockHash, vote.nBlockHeight - 101)) return false; - - uint256 nVoteHash = vote.GetHash(); - - if(HasVerifiedPaymentVote(nVoteHash)) return false; - - LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePaymentVotes); - - mapMasternodePaymentVotes[nVoteHash] = vote; - - auto it = mapMasternodeBlocks.emplace(vote.nBlockHeight, CMasternodeBlockPayees(vote.nBlockHeight)).first; - it->second.AddPayee(vote); - - LogPrint("mnpayments", "CMasternodePayments::%s -- added, hash=%s\n", __func__, nVoteHash.ToString()); - - return true; -} - -bool CMasternodePayments::HasVerifiedPaymentVote(const uint256& hashIn) const -{ - LOCK(cs_mapMasternodePaymentVotes); - const auto it = mapMasternodePaymentVotes.find(hashIn); - return it != mapMasternodePaymentVotes.end() && it->second.IsVerified(); -} - -void CMasternodeBlockPayees::AddPayee(const CMasternodePaymentVote& vote) -{ - LOCK(cs_vecPayees); - - uint256 nVoteHash = vote.GetHash(); - - for (auto& payee : vecPayees) { - if (payee.GetPayee() == vote.payee) { - payee.AddVoteHash(nVoteHash); - return; - } - } - CMasternodePayee payeeNew(vote.payee, nVoteHash); - vecPayees.push_back(payeeNew); -} - -bool CMasternodeBlockPayees::GetBestPayee(CScript& payeeRet) const -{ - LOCK(cs_vecPayees); - - if(vecPayees.empty()) { - LogPrint("mnpayments", "CMasternodeBlockPayees::%s -- ERROR: couldn't find any payee\n", __func__); - return false; - } - - int nVotes = -1; - for (const auto& payee : vecPayees) { - if (payee.GetVoteCount() > nVotes) { - payeeRet = payee.GetPayee(); - nVotes = payee.GetVoteCount(); - } - } - - return (nVotes > -1); -} - -bool CMasternodeBlockPayees::HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq) const -{ - LOCK(cs_vecPayees); - - for (const auto& payee : vecPayees) { - if (payee.GetVoteCount() >= nVotesReq && payee.GetPayee() == payeeIn) { - return true; - } - } - - LogPrint("mnpayments", "CMasternodeBlockPayees::%s -- ERROR: couldn't find any payee with %d+ votes\n", __func__, nVotesReq); - return false; -} - -bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) const -{ - LOCK(cs_vecPayees); - - int nMaxSignatures = 0; - std::string strPayeesPossible = ""; - - CAmount nMasternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut()); - - //require at least MNPAYMENTS_SIGNATURES_REQUIRED signatures - - for (const auto& payee : vecPayees) { - if (payee.GetVoteCount() >= nMaxSignatures) { - nMaxSignatures = payee.GetVoteCount(); - } - } - - // if we don't have at least MNPAYMENTS_SIGNATURES_REQUIRED signatures on a payee, approve whichever is the longest chain - if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; - - for (const auto& payee : vecPayees) { - if (payee.GetVoteCount() >= MNPAYMENTS_SIGNATURES_REQUIRED) { - for (const auto& txout : txNew.vout) { - if (payee.GetPayee() == txout.scriptPubKey && nMasternodePayment == txout.nValue) { - LogPrint("mnpayments", "CMasternodeBlockPayees::%s -- Found required payment\n", __func__); - return true; - } - } - - CTxDestination address1; - ExtractDestination(payee.GetPayee(), address1); - CBitcoinAddress address2(address1); - - if(strPayeesPossible == "") { - strPayeesPossible = address2.ToString(); - } else { - strPayeesPossible += "," + address2.ToString(); - } - } - } - - LogPrintf("CMasternodeBlockPayees::%s -- ERROR: Missing required payment, possible payees: '%s', amount: %f DASH\n", __func__, strPayeesPossible, (float)nMasternodePayment/COIN); - return false; -} - -std::string CMasternodeBlockPayees::GetRequiredPaymentsString() const -{ - LOCK(cs_vecPayees); - - std::string strRequiredPayments = ""; - - for (const auto& payee : vecPayees) - { - CTxDestination address1; - ExtractDestination(payee.GetPayee(), address1); - CBitcoinAddress address2(address1); - - if (!strRequiredPayments.empty()) - strRequiredPayments += ", "; - - strRequiredPayments += strprintf("%s:%d", address2.ToString(), payee.GetVoteCount()); - } - - if (strRequiredPayments.empty()) - return "Unknown"; - - return strRequiredPayments; -} - -std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight) const -{ - LOCK(cs_mapMasternodeBlocks); - const auto it = mapMasternodeBlocks.find(nBlockHeight); - return it == mapMasternodeBlocks.end() ? "Unknown" : it->second.GetRequiredPaymentsString(); -} - bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const { - if (deterministicMNManager->IsDIP3Active(nBlockHeight)) { - std::vector voutMasternodePayments; - if (!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePayments)) { - LogPrintf("CMasternodePayments::%s -- ERROR failed to get payees for block at height %s\n", __func__, nBlockHeight); - return true; - } - - for (const auto& txout : voutMasternodePayments) { - bool found = false; - for (const auto& txout2 : txNew.vout) { - if (txout == txout2) { - found = true; - break; - } - } - if (!found) { - CTxDestination dest; - if (!ExtractDestination(txout.scriptPubKey, dest)) - assert(false); - LogPrintf("CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, CBitcoinAddress(dest).ToString(), nBlockHeight); - return false; - } - } - return true; - } else { - LOCK(cs_mapMasternodeBlocks); - const auto it = mapMasternodeBlocks.find(nBlockHeight); - return it == mapMasternodeBlocks.end() ? true : it->second.IsTransactionValid(txNew); - } -} - -void CMasternodePayments::CheckAndRemove() -{ - if (deterministicMNManager->IsDIP3Active()) { - return; - } - - if(!masternodeSync.IsBlockchainSynced()) return; - - LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePaymentVotes); - - int nLimit = GetStorageLimit(); - - std::map::iterator it = mapMasternodePaymentVotes.begin(); - while(it != mapMasternodePaymentVotes.end()) { - CMasternodePaymentVote vote = (*it).second; - - if(nCachedBlockHeight - vote.nBlockHeight > nLimit) { - LogPrint("mnpayments", "CMasternodePayments::%s -- Removing old Masternode payment: nBlockHeight=%d\n", __func__, vote.nBlockHeight); - mapMasternodePaymentVotes.erase(it++); - mapMasternodeBlocks.erase(vote.nBlockHeight); - } else { - ++it; - } - } - LogPrintf("CMasternodePayments::%s -- %s\n", __func__, ToString()); -} - -bool CMasternodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::string& strError, CConnman& connman) const -{ - masternode_info_t mnInfo; - - if(!mnodeman.GetMasternodeInfo(masternodeOutpoint, mnInfo)) { - strError = strprintf("Unknown masternode=%s", masternodeOutpoint.ToStringShort()); - // Only ask if we are already synced and still have no idea about that Masternode - if(masternodeSync.IsMasternodeListSynced()) { - mnodeman.AskForMN(pnode, masternodeOutpoint, connman); - } - - return false; - } - - int nMinRequiredProtocol; - if(nBlockHeight >= nValidationHeight) { - // new votes must comply SPORK_10_MASTERNODE_PAY_UPDATED_NODES rules - nMinRequiredProtocol = mnpayments.GetMinMasternodePaymentsProto(); - } else { - // allow non-updated masternodes for old blocks - nMinRequiredProtocol = MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1; - } - - if(mnInfo.nProtocolVersion < nMinRequiredProtocol) { - strError = strprintf("Masternode protocol is too old: nProtocolVersion=%d, nMinRequiredProtocol=%d", mnInfo.nProtocolVersion, nMinRequiredProtocol); - return false; - } - - // Only masternodes should try to check masternode rank for old votes - they need to pick the right winner for future blocks. - // Regular clients (miners included) need to verify masternode rank for future block votes only. - if(!fMasternodeMode && nBlockHeight < nValidationHeight) return true; - - int nRank; - - if(!mnodeman.GetMasternodeRank(masternodeOutpoint, nRank, nBlockHeight - 101, nMinRequiredProtocol)) { - LogPrint("mnpayments", "CMasternodePaymentVote::%s -- Can't calculate rank for masternode %s\n", __func__, - masternodeOutpoint.ToStringShort()); - return false; - } - - if(nRank > MNPAYMENTS_SIGNATURES_TOTAL) { - // It's common to have masternodes mistakenly think they are in the top 10 - // We don't want to print all of these messages in normal mode, debug mode should print though - strError = strprintf("Masternode %s is not in the top %d (%d)", masternodeOutpoint.ToStringShort(), MNPAYMENTS_SIGNATURES_TOTAL, nRank); - // Only ban for new mnw which is out of bounds, for old mnw MN list itself might be way too much off - if(nRank > MNPAYMENTS_SIGNATURES_TOTAL*2 && nBlockHeight > nValidationHeight) { - LOCK(cs_main); - strError = strprintf("Masternode %s is not in the top %d (%d)", masternodeOutpoint.ToStringShort(), MNPAYMENTS_SIGNATURES_TOTAL*2, nRank); - LogPrintf("CMasternodePaymentVote::%s -- Error: %s\n", __func__, strError); - Misbehaving(pnode->GetId(), 20); - } - // Still invalid however - return false; - } - - return true; -} - -bool CMasternodePayments::ProcessBlock(int nBlockHeight, CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active(nBlockHeight)) { + if (!deterministicMNManager->IsDIP3Active(nBlockHeight)) { + // can't verify historical blocks here return true; } - // DETERMINE IF WE SHOULD BE VOTING FOR THE NEXT PAYEE - - if(fLiteMode || !fMasternodeMode) return false; - - // We have little chances to pick the right winner if winners list is out of sync - // but we have no choice, so we'll try. However it doesn't make sense to even try to do so - // if we have not enough data about masternodes. - if(!masternodeSync.IsMasternodeListSynced()) return false; - - int nRank; - - if (!mnodeman.GetMasternodeRank(activeMasternodeInfo.outpoint, nRank, nBlockHeight - 101, GetMinMasternodePaymentsProto())) { - LogPrint("mnpayments", "CMasternodePayments::%s -- Unknown Masternode\n", __func__); - return false; + std::vector voutMasternodePayments; + if (!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePayments)) { + LogPrintf("CMasternodePayments::%s -- ERROR failed to get payees for block at height %s\n", __func__, nBlockHeight); + return true; } - if (nRank > MNPAYMENTS_SIGNATURES_TOTAL) { - LogPrint("mnpayments", "CMasternodePayments::%s -- Masternode not in the top %d (%d)\n", __func__, MNPAYMENTS_SIGNATURES_TOTAL, nRank); - return false; - } - - - // LOCATE THE NEXT MASTERNODE WHICH SHOULD BE PAID - - LogPrintf("CMasternodePayments::%s -- Start: nBlockHeight=%d, masternode=%s\n", __func__, nBlockHeight, activeMasternodeInfo.outpoint.ToStringShort()); - - // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough - int nCount = 0; - masternode_info_t mnInfo; - - if (!mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount, mnInfo)) { - LogPrintf("CMasternodePayments::%s -- ERROR: Failed to find masternode to pay\n", __func__); - return false; - } - - LogPrintf("CMasternodePayments::%s -- Masternode found by GetNextMasternodeInQueueForPayment(): %s\n", __func__, mnInfo.outpoint.ToStringShort()); - - - CScript payee = GetScriptForDestination(mnInfo.keyIDCollateralAddress); - - CMasternodePaymentVote voteNew(activeMasternodeInfo.outpoint, nBlockHeight, payee); - - CTxDestination address1; - ExtractDestination(payee, address1); - CBitcoinAddress address2(address1); - - LogPrintf("CMasternodePayments::%s -- vote: payee=%s, nBlockHeight=%d\n", __func__, address2.ToString(), nBlockHeight); - - // SIGN MESSAGE TO NETWORK WITH OUR MASTERNODE KEYS - - LogPrintf("CMasternodePayments::%s -- Signing vote\n", __func__); - if (voteNew.Sign()) { - LogPrintf("CMasternodePayments::%s -- AddOrUpdatePaymentVote()\n", __func__); - - if (AddOrUpdatePaymentVote(voteNew)) { - voteNew.Relay(connman); - return true; - } - } - - return false; -} - -void CMasternodePayments::CheckBlockVotes(int nBlockHeight) -{ - if (!masternodeSync.IsWinnersListSynced()) return; - - CMasternodeMan::rank_pair_vec_t mns; - if (!mnodeman.GetMasternodeRanks(mns, nBlockHeight - 101, GetMinMasternodePaymentsProto())) { - LogPrintf("CMasternodePayments::%s -- nBlockHeight=%d, GetMasternodeRanks failed\n", __func__, nBlockHeight); - return; - } - - std::string debugStr; - - debugStr += strprintf("CMasternodePayments::%s -- nBlockHeight=%d,\n Expected voting MNs:\n", __func__, nBlockHeight); - - LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePaymentVotes); - - int i{0}; - for (const auto& mn : mns) { - CScript payee; + for (const auto& txout : voutMasternodePayments) { bool found = false; - - const auto it = mapMasternodeBlocks.find(nBlockHeight); - if (it != mapMasternodeBlocks.end()) { - for (const auto& p : it->second.vecPayees) { - for (const auto& voteHash : p.GetVoteHashes()) { - const auto itVote = mapMasternodePaymentVotes.find(voteHash); - if (itVote == mapMasternodePaymentVotes.end()) { - debugStr += strprintf(" - could not find vote %s\n", - voteHash.ToString()); - continue; - } - if (itVote->second.masternodeOutpoint == mn.second->collateralOutpoint) { - payee = itVote->second.payee; - found = true; - break; - } - } - } - } - - if (found) { - CTxDestination address1; - ExtractDestination(payee, address1); - CBitcoinAddress address2(address1); - - debugStr += strprintf(" - %s - voted for %s\n", - mn.second->collateralOutpoint.ToStringShort(), address2.ToString()); - } else { - mapMasternodesDidNotVote.emplace(mn.second->collateralOutpoint, 0).first->second++; - - debugStr += strprintf(" - %s - no vote received\n", - mn.second->collateralOutpoint.ToStringShort()); - } - - if (++i >= MNPAYMENTS_SIGNATURES_TOTAL) break; - } - - if (mapMasternodesDidNotVote.empty()) { - LogPrint("mnpayments", "%s", debugStr); - return; - } - - debugStr += " Masternodes which missed a vote in the past:\n"; - for (const auto& item : mapMasternodesDidNotVote) { - debugStr += strprintf(" - %s: %d\n", item.first.ToStringShort(), item.second); - } - - LogPrint("mnpayments", "%s", debugStr); -} - -void CMasternodePaymentVote::Relay(CConnman& connman) const -{ - if (deterministicMNManager->IsDIP3Active()) { - return; - } - - // Do not relay until fully synced - if(!masternodeSync.IsSynced()) { - LogPrint("mnpayments", "CMasternodePayments::%s -- won't relay until fully synced\n", __func__); - return; - } - - CInv inv(MSG_MASTERNODE_PAYMENT_VOTE, GetHash()); - connman.RelayInv(inv); -} - -bool CMasternodePaymentVote::CheckSignature(const CKeyID& keyIDOperator, int nValidationHeight, int &nDos) const -{ - // do not ban by default - nDos = 0; - std::string strError = ""; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) { - // could be a signature in old format - std::string strMessage = masternodeOutpoint.ToStringShort() + - std::to_string(nBlockHeight) + - ScriptToAsmStr(payee); - if(!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - // nope, not in old format either - // Only ban for future block vote when we are already synced. - // Otherwise it could be the case when MN which signed this vote is using another key now - // and we have no idea about the old one. - if(masternodeSync.IsMasternodeListSynced() && nBlockHeight > nValidationHeight) { - nDos = 20; - } - return error("CMasternodePaymentVote::CheckSignature -- Got bad Masternode payment signature, masternode=%s, error: %s", - masternodeOutpoint.ToStringShort(), strError); - } - } - } else { - std::string strMessage = masternodeOutpoint.ToStringShort() + - std::to_string(nBlockHeight) + - ScriptToAsmStr(payee); - - if (!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - // Only ban for future block vote when we are already synced. - // Otherwise it could be the case when MN which signed this vote is using another key now - // and we have no idea about the old one. - if(masternodeSync.IsMasternodeListSynced() && nBlockHeight > nValidationHeight) { - nDos = 20; - } - return error("CMasternodePaymentVote::CheckSignature -- Got bad Masternode payment signature, masternode=%s, error: %s", - masternodeOutpoint.ToStringShort(), strError); - } - } - - return true; -} - -std::string CMasternodePaymentVote::ToString() const -{ - std::ostringstream info; - - info << masternodeOutpoint.ToStringShort() << - ", " << nBlockHeight << - ", " << ScriptToAsmStr(payee) << - ", " << (int)vchSig.size(); - - return info.str(); -} - -// Send only votes for future blocks, node should request every other missing payment block individually -void CMasternodePayments::Sync(CNode* pnode, CConnman& connman) const -{ - LOCK(cs_mapMasternodeBlocks); - - if(!masternodeSync.IsWinnersListSynced()) return; - - int nInvCount = 0; - - for(int h = nCachedBlockHeight; h < nCachedBlockHeight + 20; h++) { - const auto it = mapMasternodeBlocks.find(h); - if(it != mapMasternodeBlocks.end()) { - for (const auto& payee : it->second.vecPayees) { - std::vector vecVoteHashes = payee.GetVoteHashes(); - for (const auto& hash : vecVoteHashes) { - if(!HasVerifiedPaymentVote(hash)) continue; - pnode->PushInventory(CInv(MSG_MASTERNODE_PAYMENT_VOTE, hash)); - nInvCount++; - } - } - } - } - - LogPrintf("CMasternodePayments::%s -- Sent %d votes to peer=%d\n", __func__, nInvCount, pnode->id); - CNetMsgMaker msgMaker(pnode->GetSendVersion()); - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount)); -} - -// Request low data/unknown payment blocks in batches directly from some node instead of/after preliminary Sync. -void CMasternodePayments::RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connman) const -{ - if(!masternodeSync.IsMasternodeListSynced()) return; - - CNetMsgMaker msgMaker(pnode->GetSendVersion()); - LOCK2(cs_main, cs_mapMasternodeBlocks); - - std::vector vToFetch; - int nLimit = GetStorageLimit(); - - const CBlockIndex *pindex = chainActive.Tip(); - - while(nCachedBlockHeight - pindex->nHeight < nLimit) { - const auto it = mapMasternodeBlocks.find(pindex->nHeight); - if(it == mapMasternodeBlocks.end()) { - // We have no idea about this block height, let's ask - vToFetch.push_back(CInv(MSG_MASTERNODE_PAYMENT_BLOCK, pindex->GetBlockHash())); - // We should not violate GETDATA rules - if(vToFetch.size() == MAX_INV_SZ) { - LogPrintf("CMasternodePayments::%s -- asking peer=%d for %d blocks\n", __func__, pnode->id, MAX_INV_SZ); - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); - // Start filling new batch - vToFetch.clear(); - } - } - if(!pindex->pprev) break; - pindex = pindex->pprev; - } - - for (auto& mnBlockPayees : mapMasternodeBlocks) { - int nBlockHeight = mnBlockPayees.first; - int nTotalVotes = 0; - bool fFound = false; - for (const auto& payee : mnBlockPayees.second.vecPayees) { - if(payee.GetVoteCount() >= MNPAYMENTS_SIGNATURES_REQUIRED) { - fFound = true; + for (const auto& txout2 : txNew.vout) { + if (txout == txout2) { + found = true; break; } - nTotalVotes += payee.GetVoteCount(); } - // A clear winner (MNPAYMENTS_SIGNATURES_REQUIRED+ votes) was found - // or no clear winner was found but there are at least avg number of votes - if(fFound || nTotalVotes >= (MNPAYMENTS_SIGNATURES_TOTAL + MNPAYMENTS_SIGNATURES_REQUIRED)/2) { - // so just move to the next block - continue; - } - // DEBUG - DBG ( - // Let's see why this failed - for (const auto& payee : mnBlockPayees.second.vecPayees) { - CTxDestination address1; - ExtractDestination(payee.GetPayee(), address1); - CBitcoinAddress address2(address1); - printf("payee %s votes %d\n", address2.ToString().c_str(), payee.GetVoteCount()); - } - printf("block %d votes total %d\n", nBlockHeight, nTotalVotes); - ) - // END DEBUG - // Low data block found, let's try to sync it - uint256 hash; - if(GetBlockHash(hash, nBlockHeight)) { - vToFetch.push_back(CInv(MSG_MASTERNODE_PAYMENT_BLOCK, hash)); - } - // We should not violate GETDATA rules - if(vToFetch.size() == MAX_INV_SZ) { - LogPrintf("CMasternodePayments::%s -- asking peer=%d for %d payment blocks\n", __func__, pnode->id, MAX_INV_SZ); - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); - // Start filling new batch - vToFetch.clear(); + if (!found) { + CTxDestination dest; + if (!ExtractDestination(txout.scriptPubKey, dest)) + assert(false); + LogPrintf("CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, CBitcoinAddress(dest).ToString(), nBlockHeight); + return false; } } - // Ask for the rest of it - if(!vToFetch.empty()) { - LogPrintf("CMasternodePayments::%s -- asking peer=%d for %d payment blocks\n", __func__, pnode->id, vToFetch.size()); - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); - } -} - -std::string CMasternodePayments::ToString() const -{ - std::ostringstream info; - - info << "Votes: " << (int)mapMasternodePaymentVotes.size() << - ", Blocks: " << (int)mapMasternodeBlocks.size(); - - return info.str(); -} - -bool CMasternodePayments::IsEnoughData() const -{ - float nAverageVotes = (MNPAYMENTS_SIGNATURES_TOTAL + MNPAYMENTS_SIGNATURES_REQUIRED) / 2; - int nStorageLimit = GetStorageLimit(); - return GetBlockCount() > nStorageLimit && GetVoteCount() > nStorageLimit * nAverageVotes; -} - -int CMasternodePayments::GetStorageLimit() const -{ - return std::max(int(mnodeman.size() * nStorageCoeff), nMinBlocksToStore); -} - -void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindex, CConnman& connman) -{ - if(!pindex) return; - - if (deterministicMNManager->IsDIP3Active(pindex->nHeight)) { - return; - } - - nCachedBlockHeight = pindex->nHeight; - LogPrint("mnpayments", "CMasternodePayments::%s -- nCachedBlockHeight=%d\n", __func__, nCachedBlockHeight); - - int nFutureBlock = nCachedBlockHeight + 10; - - CheckBlockVotes(nFutureBlock - 1); - ProcessBlock(nFutureBlock, connman); -} - -void CMasternodePayments::DoMaintenance() -{ - if (ShutdownRequested()) return; - - CheckAndRemove(); + return true; } diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 9a41dae0c3..6db08f3ef2 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -13,23 +13,6 @@ #include "utilstrencodings.h" class CMasternodePayments; -class CMasternodePaymentVote; -class CMasternodeBlockPayees; - -static const int MNPAYMENTS_SIGNATURES_REQUIRED = 6; -static const int MNPAYMENTS_SIGNATURES_TOTAL = 10; - -//! minimum peer version that can receive and send masternode payment messages, -// vote for masternode and be elected as a payment winner -// V1 - Last protocol version before update -// V2 - Newest protocol version -static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70210; -static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70210; - -extern CCriticalSection cs_vecPayees; -extern CCriticalSection cs_mapMasternodeBlocks; - -extern CMasternodePayments mnpayments; /// TODO: all 4 functions do not belong here really, they should be refactored/moved somewhere (main.cpp ?) bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string& strErrorRet); @@ -37,123 +20,7 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, std::vector& voutMasternodePaymentsRet, std::vector& voutSuperblockPaymentsRet); std::map GetRequiredPaymentsStrings(int nStartHeight, int nEndHeight); -class CMasternodePayee -{ -private: - CScript scriptPubKey; - std::vector vecVoteHashes; - -public: - CMasternodePayee() : - scriptPubKey(), - vecVoteHashes() - {} - - CMasternodePayee(CScript payee, uint256 hashIn) : - scriptPubKey(payee), - vecVoteHashes() - { - vecVoteHashes.push_back(hashIn); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*(CScriptBase*)(&scriptPubKey)); - READWRITE(vecVoteHashes); - } - - CScript GetPayee() const { return scriptPubKey; } - - void AddVoteHash(uint256 hashIn) { vecVoteHashes.push_back(hashIn); } - std::vector GetVoteHashes() const { return vecVoteHashes; } - int GetVoteCount() const { return vecVoteHashes.size(); } -}; - -// Keep track of votes for payees from masternodes -class CMasternodeBlockPayees -{ -public: - int nBlockHeight; - std::vector vecPayees; - - CMasternodeBlockPayees() : - nBlockHeight(0), - vecPayees() - {} - CMasternodeBlockPayees(int nBlockHeightIn) : - nBlockHeight(nBlockHeightIn), - vecPayees() - {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(nBlockHeight); - READWRITE(vecPayees); - } - - void AddPayee(const CMasternodePaymentVote& vote); - bool GetBestPayee(CScript& payeeRet) const; - bool HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq) const; - - bool IsTransactionValid(const CTransaction& txNew) const; - - std::string GetRequiredPaymentsString() const; -}; - -// vote for the winning payment -class CMasternodePaymentVote -{ -public: - COutPoint masternodeOutpoint; - - int nBlockHeight; - CScript payee; - std::vector vchSig; - - CMasternodePaymentVote() : - masternodeOutpoint(), - nBlockHeight(0), - payee(), - vchSig() - {} - - CMasternodePaymentVote(COutPoint outpoint, int nBlockHeight, CScript payee) : - masternodeOutpoint(outpoint), - nBlockHeight(nBlockHeight), - payee(payee), - vchSig() - {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(masternodeOutpoint); - READWRITE(nBlockHeight); - READWRITE(*(CScriptBase*)(&payee)); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(vchSig); - } - } - - uint256 GetHash() const; - uint256 GetSignatureHash() const; - - bool Sign(); - bool CheckSignature(const CKeyID& keyIDOperator, int nValidationHeight, int &nDos) const; - - bool IsValid(CNode* pnode, int nValidationHeight, std::string& strError, CConnman& connman) const; - void Relay(CConnman& connman) const; - - bool IsVerified() const { return !vchSig.empty(); } - void MarkAsNotVerified() { vchSig.clear(); } - - std::string ToString() const; -}; +extern CMasternodePayments mnpayments; // // Masternode Payments Class @@ -162,63 +29,12 @@ public: class CMasternodePayments { -private: - // masternode count times nStorageCoeff payments blocks should be stored ... - const float nStorageCoeff; - // ... but at least nMinBlocksToStore (payments blocks) - const int nMinBlocksToStore; - - // Keep track of current block height - int nCachedBlockHeight; - public: - std::map mapMasternodePaymentVotes; - std::map mapMasternodeBlocks; - std::map mapMasternodesLastVote; - std::map mapMasternodesDidNotVote; - - CMasternodePayments() : nStorageCoeff(1.25), nMinBlocksToStore(6000) {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(mapMasternodePaymentVotes); - READWRITE(mapMasternodeBlocks); - } - - void Clear(); - - bool AddOrUpdatePaymentVote(const CMasternodePaymentVote& vote); - bool HasVerifiedPaymentVote(const uint256& hashIn) const; - bool ProcessBlock(int nBlockHeight, CConnman& connman); - void CheckBlockVotes(int nBlockHeight); - - void Sync(CNode* node, CConnman& connman) const; - void RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connman) const; - void CheckAndRemove(); - bool GetBlockTxOuts(int nBlockHeight, CAmount blockReward, std::vector& voutMasternodePaymentsRet) const; bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const; bool IsScheduled(const CDeterministicMNCPtr& dmn, int nNotBlockHeight) const; - bool UpdateLastVote(const CMasternodePaymentVote& vote); - - int GetMinMasternodePaymentsProto() const; - void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); - std::string GetRequiredPaymentsString(int nBlockHeight) const; bool GetMasternodeTxOuts(int nBlockHeight, CAmount blockReward, std::vector& voutMasternodePaymentsRet) const; - std::string ToString() const; - - int GetBlockCount() const { return mapMasternodeBlocks.size(); } - int GetVoteCount() const { return mapMasternodePaymentVotes.size(); } - - bool IsEnoughData() const; - int GetStorageLimit() const; - - void UpdatedBlockTip(const CBlockIndex *pindex, CConnman& connman); - - void DoMaintenance(); }; #endif diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index b165918dda..382dc546ef 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -45,8 +45,6 @@ std::string CMasternodeSync::GetAssetName() { case(MASTERNODE_SYNC_INITIAL): return "MASTERNODE_SYNC_INITIAL"; case(MASTERNODE_SYNC_WAITING): return "MASTERNODE_SYNC_WAITING"; - case(MASTERNODE_SYNC_LIST): return "MASTERNODE_SYNC_LIST"; - case(MASTERNODE_SYNC_MNW): return "MASTERNODE_SYNC_MNW"; case(MASTERNODE_SYNC_GOVERNANCE): return "MASTERNODE_SYNC_GOVERNANCE"; case(MASTERNODE_SYNC_FAILED): return "MASTERNODE_SYNC_FAILED"; case MASTERNODE_SYNC_FINISHED: return "MASTERNODE_SYNC_FINISHED"; @@ -66,24 +64,6 @@ void CMasternodeSync::SwitchToNextAsset(CConnman& connman) LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); break; case(MASTERNODE_SYNC_WAITING): - LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); - if (deterministicMNManager->IsDIP3Active()) { - nCurrentAsset = MASTERNODE_SYNC_GOVERNANCE; - } else { - nCurrentAsset = MASTERNODE_SYNC_LIST; - } - LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); - break; - case(MASTERNODE_SYNC_LIST): - LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); - if (deterministicMNManager->IsDIP3Active()) { - nCurrentAsset = MASTERNODE_SYNC_GOVERNANCE; - } else { - nCurrentAsset = MASTERNODE_SYNC_MNW; - } - LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); - break; - case(MASTERNODE_SYNC_MNW): LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nCurrentAsset = MASTERNODE_SYNC_GOVERNANCE; LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); @@ -92,8 +72,6 @@ void CMasternodeSync::SwitchToNextAsset(CConnman& connman) LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nCurrentAsset = MASTERNODE_SYNC_FINISHED; uiInterface.NotifyAdditionalDataSyncProgressChanged(1); - //try to activate our masternode if possible - legacyActiveMasternodeManager.ManageState(connman); connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) { netfulfilledman.AddFulfilledRequest(pnode->addr, "full-sync"); @@ -112,8 +90,6 @@ std::string CMasternodeSync::GetSyncStatus() switch (masternodeSync.nCurrentAsset) { case MASTERNODE_SYNC_INITIAL: return _("Synchroning blockchain..."); case MASTERNODE_SYNC_WAITING: return _("Synchronization pending..."); - case MASTERNODE_SYNC_LIST: return _("Synchronizing masternodes..."); - case MASTERNODE_SYNC_MNW: return _("Synchronizing masternode payments..."); case MASTERNODE_SYNC_GOVERNANCE: return _("Synchronizing governance objects..."); case MASTERNODE_SYNC_FAILED: return _("Synchronization failed"); case MASTERNODE_SYNC_FINISHED: return _("Synchronization finished"); @@ -199,16 +175,6 @@ void CMasternodeSync::ProcessTick(CConnman& connman) if (nCurrentAsset == MASTERNODE_SYNC_WAITING) { connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS)); //get current network sporks SwitchToNextAsset(connman); - } else if (nCurrentAsset == MASTERNODE_SYNC_LIST) { - if (!deterministicMNManager->IsDIP3Active()) { - mnodeman.DsegUpdate(pnode, connman); - } - SwitchToNextAsset(connman); - } else if (nCurrentAsset == MASTERNODE_SYNC_MNW) { - if (!deterministicMNManager->IsDIP3Active()) { - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC)); //sync payment votes - } - SwitchToNextAsset(connman); } else if (nCurrentAsset == MASTERNODE_SYNC_GOVERNANCE) { SendGovernanceSyncRequest(pnode, connman); SwitchToNextAsset(connman); @@ -253,109 +219,6 @@ void CMasternodeSync::ProcessTick(CConnman& connman) } } - // MNLIST : SYNC MASTERNODE LIST FROM OTHER CONNECTED CLIENTS - - if(nCurrentAsset == MASTERNODE_SYNC_LIST) { - if (deterministicMNManager->IsDIP3Active()) { - SwitchToNextAsset(connman); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - LogPrint("masternode", "CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nCurrentAsset, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped); - // check for timeout first - if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) { - LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- timeout\n", nTick, nCurrentAsset); - if (nTriedPeerCount == 0) { - LogPrintf("CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName()); - // there is no way we can continue without masternode list, fail here and try later - Fail(); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - SwitchToNextAsset(connman); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - // request from three peers max - if (nTriedPeerCount > 2) { - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - // only request once from each peer - if(netfulfilledman.HasFulfilledRequest(pnode->addr, "masternode-list-sync")) continue; - netfulfilledman.AddFulfilledRequest(pnode->addr, "masternode-list-sync"); - - if (pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; - nTriedPeerCount++; - - mnodeman.DsegUpdate(pnode, connman); - - connman.ReleaseNodeVector(vNodesCopy); - return; //this will cause each peer to get one request each six seconds for the various assets we need - } - - // MNW : SYNC MASTERNODE PAYMENT VOTES FROM OTHER CONNECTED CLIENTS - - if(nCurrentAsset == MASTERNODE_SYNC_MNW) { - if (deterministicMNManager->IsDIP3Active()) { - SwitchToNextAsset(connman); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - LogPrint("mnpayments", "CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nCurrentAsset, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped); - // check for timeout first - // This might take a lot longer than MASTERNODE_SYNC_TIMEOUT_SECONDS due to new blocks, - // but that should be OK and it should timeout eventually. - if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) { - LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- timeout\n", nTick, nCurrentAsset); - if (nTriedPeerCount == 0) { - LogPrintf("CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName()); - // probably not a good idea to proceed without winner list - Fail(); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - SwitchToNextAsset(connman); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - // check for data - // if mnpayments already has enough blocks and votes, switch to the next asset - // try to fetch data from at least two peers though - if(nTriedPeerCount > 1 && mnpayments.IsEnoughData()) { - LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- found enough data\n", nTick, nCurrentAsset); - SwitchToNextAsset(connman); - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - // request from three peers max - if (nTriedPeerCount > 2) { - connman.ReleaseNodeVector(vNodesCopy); - return; - } - - // only request once from each peer - if(netfulfilledman.HasFulfilledRequest(pnode->addr, "masternode-payment-sync")) continue; - netfulfilledman.AddFulfilledRequest(pnode->addr, "masternode-payment-sync"); - - if(pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; - nTriedPeerCount++; - - // ask node for all payment votes it has (new nodes will only return votes for future payments) - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC)); - // ask node for missing pieces only (old nodes will not be asked) - mnpayments.RequestLowDataPaymentBlocks(pnode, connman); - - connman.ReleaseNodeVector(vNodesCopy); - return; //this will cause each peer to get one request each six seconds for the various assets we need - } - // GOVOBJ : SYNC GOVERNANCE ITEMS FROM OUR PEERS if(nCurrentAsset == MASTERNODE_SYNC_GOVERNANCE) { diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 2d98c8a1cb..13d2601c63 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -12,8 +12,6 @@ class CMasternodeSync; static const int MASTERNODE_SYNC_FAILED = -1; static const int MASTERNODE_SYNC_INITIAL = 0; // sync just started, was reset recently or still in IDB static const int MASTERNODE_SYNC_WAITING = 1; // waiting after initial to see if we can get more headers/blocks -static const int MASTERNODE_SYNC_LIST = 2; -static const int MASTERNODE_SYNC_MNW = 3; static const int MASTERNODE_SYNC_GOVERNANCE = 4; static const int MASTERNODE_SYNC_GOVOBJ = 10; static const int MASTERNODE_SYNC_GOVOBJ_VOTE = 11; @@ -53,8 +51,6 @@ public: bool IsFailed() { return nCurrentAsset == MASTERNODE_SYNC_FAILED; } bool IsBlockchainSynced() { return nCurrentAsset > MASTERNODE_SYNC_WAITING; } - bool IsMasternodeListSynced() { return nCurrentAsset > MASTERNODE_SYNC_LIST; } - bool IsWinnersListSynced() { return nCurrentAsset > MASTERNODE_SYNC_MNW; } bool IsSynced() { return nCurrentAsset == MASTERNODE_SYNC_FINISHED; } int GetAssetID() { return nCurrentAsset; } diff --git a/src/masternode.cpp b/src/masternode.cpp index f6fe9bd035..a7b90cca9c 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -24,946 +24,26 @@ CMasternode::CMasternode() : - masternode_info_t{ MASTERNODE_ENABLED, PROTOCOL_VERSION, GetAdjustedTime()} -{} - -CMasternode::CMasternode(CService addr, COutPoint outpoint, CPubKey pubKeyCollateralAddressNew, CPubKey pubKeyMasternodeNew, int nProtocolVersionIn) : - masternode_info_t{ MASTERNODE_ENABLED, nProtocolVersionIn, GetAdjustedTime(), - outpoint, addr, pubKeyCollateralAddressNew, pubKeyMasternodeNew} + masternode_info_t{ } {} CMasternode::CMasternode(const CMasternode& other) : masternode_info_t{other}, - lastPing(other.lastPing), - vchSig(other.vchSig), - nCollateralMinConfBlockHash(other.nCollateralMinConfBlockHash), - nBlockLastPaid(other.nBlockLastPaid), - nPoSeBanScore(other.nPoSeBanScore), - nPoSeBanHeight(other.nPoSeBanHeight), - nMixingTxCount(other.nMixingTxCount), - fUnitTest(other.fUnitTest) -{} - -CMasternode::CMasternode(const CMasternodeBroadcast& mnb) : - masternode_info_t{ mnb.nActiveState, mnb.nProtocolVersion, mnb.sigTime, - mnb.outpoint, mnb.addr, mnb.pubKeyCollateralAddress, mnb.pubKeyMasternode}, - lastPing(mnb.lastPing), - vchSig(mnb.vchSig) + nMixingTxCount(other.nMixingTxCount) {} CMasternode::CMasternode(const uint256 &proTxHash, const CDeterministicMNCPtr& dmn) : - masternode_info_t{ MASTERNODE_ENABLED, DMN_PROTO_VERSION, GetAdjustedTime(), - dmn->collateralOutpoint, dmn->pdmnState->addr, CKeyID() /* not valid with DIP3 */, dmn->pdmnState->keyIDOwner, dmn->pdmnState->pubKeyOperator, dmn->pdmnState->keyIDVoting} + masternode_info_t{ dmn->collateralOutpoint } { } -// -// When a new masternode broadcast is sent, update our information -// -bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb, CConnman& connman) -{ - if(mnb.sigTime <= sigTime && !mnb.fRecovery) return false; - - pubKeyMasternode = mnb.pubKeyMasternode; - keyIDOwner = mnb.pubKeyMasternode.GetID(); - legacyKeyIDOperator = mnb.pubKeyMasternode.GetID(); - keyIDVoting = mnb.pubKeyMasternode.GetID(); - sigTime = mnb.sigTime; - vchSig = mnb.vchSig; - nProtocolVersion = mnb.nProtocolVersion; - addr = mnb.addr; - nPoSeBanScore = 0; - nPoSeBanHeight = 0; - nTimeLastChecked = 0; - int nDos = 0; - if(!mnb.lastPing || (mnb.lastPing && mnb.lastPing.CheckAndUpdate(this, true, nDos, connman))) { - lastPing = mnb.lastPing; - mnodeman.mapSeenMasternodePing.insert(std::make_pair(lastPing.GetHash(), lastPing)); - } - // if it matches our Masternode privkey... - if(fMasternodeMode && legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator) { - nPoSeBanScore = -MASTERNODE_POSE_BAN_MAX_SCORE; - if(nProtocolVersion == PROTOCOL_VERSION) { - // ... and PROTOCOL_VERSION, then we've been remotely activated ... - legacyActiveMasternodeManager.ManageState(connman); - } else { - // ... otherwise we need to reactivate our node, do not add it to the list and do not relay - // but also do not ban the node we get this message from - LogPrintf("CMasternode::UpdateFromNewBroadcast -- wrong PROTOCOL_VERSION, re-activate your MN: message nProtocolVersion=%d PROTOCOL_VERSION=%d\n", nProtocolVersion, PROTOCOL_VERSION); - return false; - } - } - return true; -} - -// -// Deterministically calculate a given "score" for a Masternode depending on how close it's hash is to -// the proof of work for that block. The further away they are the better, the furthest will win the election -// and get paid this block -// -arith_uint256 CMasternode::CalculateScore(const uint256& blockHash) const -{ - // NOTE not called when deterministic masternodes (spork15) are activated - - // Deterministically calculate a "score" for a Masternode based on any given (block)hash - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << outpoint << nCollateralMinConfBlockHash << blockHash; - return UintToArith256(ss.GetHash()); -} - -CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outpoint, const CKeyID& keyID) -{ - int nHeight; - return CheckCollateral(outpoint, keyID, nHeight); -} - -CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outpoint, const CKeyID& keyID, int& nHeightRet) -{ - AssertLockHeld(cs_main); - - Coin coin; - if(!GetUTXOCoin(outpoint, coin)) { - return COLLATERAL_UTXO_NOT_FOUND; - } - - if(coin.out.nValue != 1000 * COIN) { - return COLLATERAL_INVALID_AMOUNT; - } - - if(keyID.IsNull() || coin.out.scriptPubKey != GetScriptForDestination(keyID)) { - return COLLATERAL_INVALID_PUBKEY; - } - - nHeightRet = coin.nHeight; - return COLLATERAL_OK; -} - -void CMasternode::Check(bool fForce) -{ - AssertLockHeld(cs_main); - LOCK(cs); - - if(ShutdownRequested()) return; - - if(!fForce && (GetTime() - nTimeLastChecked < MASTERNODE_CHECK_SECONDS)) return; - nTimeLastChecked = GetTime(); - - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state\n", outpoint.ToStringShort(), GetStateString()); - - //once spent, stop doing the checks - if(IsOutpointSpent()) return; - - int nHeight = 0; - if(!fUnitTest) { - Coin coin; - if(!GetUTXOCoin(outpoint, coin)) { - nActiveState = MASTERNODE_OUTPOINT_SPENT; - LogPrint("masternode", "CMasternode::Check -- Failed to find Masternode UTXO, masternode=%s\n", outpoint.ToStringShort()); - return; - } - - nHeight = chainActive.Height(); - } - - if(IsPoSeBanned()) { - if(nHeight < nPoSeBanHeight) return; // too early? - // Otherwise give it a chance to proceed further to do all the usual checks and to change its state. - // Masternode still will be on the edge and can be banned back easily if it keeps ignoring mnverify - // or connect attempts. Will require few mnverify messages to strengthen its position in mn list. - LogPrintf("CMasternode::Check -- Masternode %s is unbanned and back in list now\n", outpoint.ToStringShort()); - DecreasePoSeBanScore(); - } else if(nPoSeBanScore >= MASTERNODE_POSE_BAN_MAX_SCORE) { - nActiveState = MASTERNODE_POSE_BAN; - // ban for the whole payment cycle - nPoSeBanHeight = nHeight + mnodeman.size(); - LogPrintf("CMasternode::Check -- Masternode %s is banned till block %d now\n", outpoint.ToStringShort(), nPoSeBanHeight); - return; - } - - int nActiveStatePrev = nActiveState; - bool fOurMasternode = fMasternodeMode && activeMasternodeInfo.legacyKeyIDOperator == legacyKeyIDOperator; - - // masternode doesn't meet payment protocol requirements ... - bool fRequireUpdate = nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto() || - // or it's our own node and we just updated it to the new protocol but we are still waiting for activation ... - (fOurMasternode && nProtocolVersion < PROTOCOL_VERSION); - - if(fRequireUpdate) { - nActiveState = MASTERNODE_UPDATE_REQUIRED; - if(nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } - return; - } - - // keep old masternodes on start, give them a chance to receive updates... - bool fWaitForPing = !masternodeSync.IsMasternodeListSynced() && !IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS); - - if(fWaitForPing && !fOurMasternode) { - // ...but if it was already expired before the initial check - return right away - if(IsExpired() || IsSentinelPingExpired() || IsNewStartRequired()) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state, waiting for ping\n", outpoint.ToStringShort(), GetStateString()); - return; - } - } - - // don't expire if we are still in "waiting for ping" mode unless it's our own masternode - if(!fWaitForPing || fOurMasternode) { - - if(!IsPingedWithin(MASTERNODE_NEW_START_REQUIRED_SECONDS)) { - nActiveState = MASTERNODE_NEW_START_REQUIRED; - if(nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } - return; - } - - if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)) { - nActiveState = MASTERNODE_EXPIRED; - if(nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } - return; - } - - // part 1: expire based on dashd ping - bool fSentinelPingActive = masternodeSync.IsSynced() && mnodeman.IsSentinelPingActive(); - bool fSentinelPingExpired = fSentinelPingActive && !IsPingedWithin(MASTERNODE_SENTINEL_PING_MAX_SECONDS); - LogPrint("masternode", "CMasternode::Check -- outpoint=%s, GetAdjustedTime()=%d, fSentinelPingExpired=%d\n", - outpoint.ToStringShort(), GetAdjustedTime(), fSentinelPingExpired); - - if(fSentinelPingExpired) { - nActiveState = MASTERNODE_SENTINEL_PING_EXPIRED; - if(nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } - return; - } - } - - // We require MNs to be in PRE_ENABLED until they either start to expire or receive a ping and go into ENABLED state - // Works on mainnet/testnet only and not the case on regtest/devnet. - if (Params().NetworkIDString() != CBaseChainParams::REGTEST && Params().NetworkIDString() != CBaseChainParams::DEVNET) { - if (lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS) { - nActiveState = MASTERNODE_PRE_ENABLED; - if (nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } - return; - } - } - - if(!fWaitForPing || fOurMasternode) { - // part 2: expire based on sentinel info - bool fSentinelPingActive = masternodeSync.IsSynced() && mnodeman.IsSentinelPingActive(); - bool fSentinelPingExpired = fSentinelPingActive && !lastPing.fSentinelIsCurrent; - - LogPrint("masternode", "CMasternode::Check -- outpoint=%s, GetAdjustedTime()=%d, fSentinelPingExpired=%d\n", - outpoint.ToStringShort(), GetAdjustedTime(), fSentinelPingExpired); - - if(fSentinelPingExpired) { - nActiveState = MASTERNODE_SENTINEL_PING_EXPIRED; - if(nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } - return; - } - } - - nActiveState = MASTERNODE_ENABLED; // OK - if(nActiveStatePrev != nActiveState) { - LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); - } -} - -bool CMasternode::IsValidNetAddr() -{ - return IsValidNetAddr(addr); -} - -bool CMasternode::IsValidNetAddr(CService addrIn) -{ - // TODO: regtest is fine with any addresses for now, - // should probably be a bit smarter if one day we start to implement tests for this - return Params().NetworkIDString() == CBaseChainParams::REGTEST || - (addrIn.IsIPv4() && IsReachable(addrIn) && addrIn.IsRoutable()); -} - masternode_info_t CMasternode::GetInfo() const { masternode_info_t info{*this}; - info.nTimeLastPing = lastPing.sigTime; info.fInfoValid = true; return info; } -std::string CMasternode::StateToString(int nStateIn) -{ - switch(nStateIn) { - case MASTERNODE_PRE_ENABLED: return "PRE_ENABLED"; - case MASTERNODE_ENABLED: return "ENABLED"; - case MASTERNODE_EXPIRED: return "EXPIRED"; - case MASTERNODE_OUTPOINT_SPENT: return "OUTPOINT_SPENT"; - case MASTERNODE_UPDATE_REQUIRED: return "UPDATE_REQUIRED"; - case MASTERNODE_SENTINEL_PING_EXPIRED: return "SENTINEL_PING_EXPIRED"; - case MASTERNODE_NEW_START_REQUIRED: return "NEW_START_REQUIRED"; - case MASTERNODE_POSE_BAN: return "POSE_BAN"; - default: return "UNKNOWN"; - } -} - -std::string CMasternode::GetStateString() const -{ - return StateToString(nActiveState); -} - -std::string CMasternode::GetStatus() const -{ - // TODO: return smth a bit more human readable here - return GetStateString(); -} - -void CMasternode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack) -{ - AssertLockHeld(cs_main); - - if(!pindex) return; - - if (deterministicMNManager->IsDIP3Active(pindex->nHeight)) { - auto dmn = deterministicMNManager->GetListForBlock(pindex->GetBlockHash()).GetMNByCollateral(outpoint); - if (!dmn || dmn->pdmnState->nLastPaidHeight == -1) { - LogPrint("masternode", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- not found\n", outpoint.ToStringShort()); - } else { - nBlockLastPaid = (int)dmn->pdmnState->nLastPaidHeight; - nTimeLastPaid = chainActive[nBlockLastPaid]->nTime; - LogPrint("masternode", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- found new %d\n", outpoint.ToStringShort(), nBlockLastPaid); - } - return; - } - - const CBlockIndex *BlockReading = pindex; - - CScript mnpayee = GetScriptForDestination(keyIDCollateralAddress); - // LogPrint("mnpayments", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s\n", outpoint.ToStringShort()); - - LOCK(cs_mapMasternodeBlocks); - - for (int i = 0; BlockReading && BlockReading->nHeight > nBlockLastPaid && i < nMaxBlocksToScanBack; i++) { - if(mnpayments.mapMasternodeBlocks.count(BlockReading->nHeight) && - mnpayments.mapMasternodeBlocks[BlockReading->nHeight].HasPayeeWithVotes(mnpayee, 2)) - { - CBlock block; - if(!ReadBlockFromDisk(block, BlockReading, Params().GetConsensus())) - continue; // shouldn't really happen - - CAmount nMasternodePayment = GetMasternodePayment(BlockReading->nHeight, block.vtx[0]->GetValueOut()); - - for (const auto& txout : block.vtx[0]->vout) - if(mnpayee == txout.scriptPubKey && nMasternodePayment == txout.nValue) { - nBlockLastPaid = BlockReading->nHeight; - nTimeLastPaid = BlockReading->nTime; - LogPrint("mnpayments", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- found new %d\n", outpoint.ToStringShort(), nBlockLastPaid); - return; - } - } - - if (BlockReading->pprev == nullptr) { assert(BlockReading); break; } - BlockReading = BlockReading->pprev; - } - - // Last payment for this masternode wasn't found in latest mnpayments blocks - // or it was found in mnpayments blocks but wasn't found in the blockchain. - // LogPrint("mnpayments", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- keeping old %d\n", outpoint.ToStringShort(), nBlockLastPaid); -} - -#ifdef ENABLE_WALLET -bool CMasternodeBroadcast::Create(const std::string& strService, const std::string& strKeyMasternode, const std::string& strTxHash, const std::string& strOutputIndex, std::string& strErrorRet, CMasternodeBroadcast &mnbRet, bool fOffline) -{ - COutPoint outpoint; - CPubKey pubKeyCollateralAddressNew; - CKey keyCollateralAddressNew; - CPubKey pubKeyMasternodeNew; - CKey keyMasternodeNew; - - auto Log = [&strErrorRet](std::string sErr)->bool - { - strErrorRet = sErr; - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); - return false; - }; - - // Wait for sync to finish because mnb simply won't be relayed otherwise - if (!fOffline && !masternodeSync.IsSynced()) - return Log("Sync in progress. Must wait until sync is complete to start Masternode"); - - if (!CMessageSigner::GetKeysFromSecret(strKeyMasternode, keyMasternodeNew, pubKeyMasternodeNew)) - return Log(strprintf("Invalid masternode key %s", strKeyMasternode)); - - if (!pwalletMain->GetMasternodeOutpointAndKeys(outpoint, pubKeyCollateralAddressNew, keyCollateralAddressNew, strTxHash, strOutputIndex)) - return Log(strprintf("Could not allocate outpoint %s:%s for masternode %s", strTxHash, strOutputIndex, strService)); - - CService service; - if (!Lookup(strService.c_str(), service, 0, false)) - return Log(strprintf("Invalid address %s for masternode.", strService)); - int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort(); - if (Params().NetworkIDString() == CBaseChainParams::MAIN) { - if (service.GetPort() != mainnetDefaultPort) - return Log(strprintf("Invalid port %u for masternode %s, only %d is supported on mainnet.", service.GetPort(), strService, mainnetDefaultPort)); - } else if (service.GetPort() == mainnetDefaultPort) - return Log(strprintf("Invalid port %u for masternode %s, %d is the only supported on mainnet.", service.GetPort(), strService, mainnetDefaultPort)); - - return Create(outpoint, service, keyCollateralAddressNew, pubKeyCollateralAddressNew, keyMasternodeNew, pubKeyMasternodeNew, strErrorRet, mnbRet); -} - -bool CMasternodeBroadcast::Create(const COutPoint& outpoint, const CService& service, const CKey& keyCollateralAddressNew, const CPubKey& pubKeyCollateralAddressNew, const CKey& keyMasternodeNew, const CPubKey& pubKeyMasternodeNew, std::string &strErrorRet, CMasternodeBroadcast &mnbRet) -{ - // wait for reindex and/or import to finish - if (fImporting || fReindex) return false; - - LogPrint("masternode", "CMasternodeBroadcast::Create -- pubKeyCollateralAddressNew = %s, keyIDOperator = %s\n", - CBitcoinAddress(pubKeyCollateralAddressNew.GetID()).ToString(), - pubKeyMasternodeNew.GetID().ToString()); - - auto Log = [&strErrorRet,&mnbRet](std::string sErr)->bool - { - strErrorRet = sErr; - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); - mnbRet = CMasternodeBroadcast(); - return false; - }; - - CMasternodePing mnp(outpoint); - if (!mnp.Sign(keyMasternodeNew, pubKeyMasternodeNew.GetID())) - return Log(strprintf("Failed to sign ping, masternode=%s", outpoint.ToStringShort())); - - mnbRet = CMasternodeBroadcast(service, outpoint, pubKeyCollateralAddressNew, pubKeyMasternodeNew, PROTOCOL_VERSION); - - if (!mnbRet.IsValidNetAddr()) - return Log(strprintf("Invalid IP address, masternode=%s", outpoint.ToStringShort())); - - mnbRet.lastPing = mnp; - if (!mnbRet.Sign(keyCollateralAddressNew)) - return Log(strprintf("Failed to sign broadcast, masternode=%s", outpoint.ToStringShort())); - - return true; -} -#endif // ENABLE_WALLET - -bool CMasternodeBroadcast::SimpleCheck(int& nDos) -{ - nDos = 0; - - AssertLockHeld(cs_main); - - // make sure addr is valid - if(!IsValidNetAddr()) { - LogPrintf("CMasternodeBroadcast::SimpleCheck -- Invalid addr, rejected: masternode=%s addr=%s\n", - outpoint.ToStringShort(), addr.ToString()); - return false; - } - - // make sure signature isn't in the future (past is OK) - if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("CMasternodeBroadcast::SimpleCheck -- Signature rejected, too far into the future: masternode=%s\n", outpoint.ToStringShort()); - nDos = 1; - return false; - } - - // empty ping or incorrect sigTime/unknown blockhash - if(!lastPing || !lastPing.SimpleCheck(nDos)) { - // one of us is probably forked or smth, just mark it as expired and check the rest of the rules - nActiveState = MASTERNODE_EXPIRED; - } - - if(nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto()) { - LogPrintf("CMasternodeBroadcast::SimpleCheck -- outdated Masternode: masternode=%s nProtocolVersion=%d\n", outpoint.ToStringShort(), nProtocolVersion); - nActiveState = MASTERNODE_UPDATE_REQUIRED; - } - - CScript pubkeyScript; - pubkeyScript = GetScriptForDestination(keyIDCollateralAddress); - - if(pubkeyScript.size() != 25) { - LogPrintf("CMasternodeBroadcast::SimpleCheck -- keyIDCollateralAddress has the wrong size\n"); - nDos = 100; - return false; - } - - CScript pubkeyScript2; - pubkeyScript2 = GetScriptForDestination(legacyKeyIDOperator); - - if(pubkeyScript2.size() != 25) { - LogPrintf("CMasternodeBroadcast::SimpleCheck -- keyIDOperator has the wrong size\n"); - nDos = 100; - return false; - } - - int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort(); - if(Params().NetworkIDString() == CBaseChainParams::MAIN) { - if(addr.GetPort() != mainnetDefaultPort) return false; - } else if(addr.GetPort() == mainnetDefaultPort) return false; - - return true; -} - -bool CMasternodeBroadcast::Update(CMasternode* pmn, int& nDos, CConnman& connman) -{ - nDos = 0; - - AssertLockHeld(cs_main); - - if(pmn->sigTime == sigTime && !fRecovery) { - // mapSeenMasternodeBroadcast in CMasternodeMan::CheckMnbAndUpdateMasternodeList should filter legit duplicates - // but this still can happen if we just started, which is ok, just do nothing here. - return false; - } - - // this broadcast is older than the one that we already have - it's bad and should never happen - // unless someone is doing something fishy - if(pmn->sigTime > sigTime) { - LogPrintf("CMasternodeBroadcast::Update -- Bad sigTime %d (existing broadcast is at %d) for Masternode %s %s\n", - sigTime, pmn->sigTime, outpoint.ToStringShort(), addr.ToString()); - return false; - } - - pmn->Check(); - - // masternode is banned by PoSe - if(pmn->IsPoSeBanned()) { - LogPrintf("CMasternodeBroadcast::Update -- Banned by PoSe, masternode=%s\n", outpoint.ToStringShort()); - return false; - } - - // IsVnAssociatedWithPubkey is validated once in CheckOutpoint, after that they just need to match - if(pmn->keyIDCollateralAddress != keyIDCollateralAddress) { - LogPrintf("CMasternodeBroadcast::Update -- Got mismatched keyIDCollateralAddress and outpoint\n"); - nDos = 33; - return false; - } - - if (!CheckSignature(nDos)) { - LogPrintf("CMasternodeBroadcast::Update -- CheckSignature() failed, masternode=%s\n", outpoint.ToStringShort()); - return false; - } - - // if ther was no masternode broadcast recently or if it matches our Masternode privkey... - if(!pmn->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS) || (fMasternodeMode && legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator)) { - // take the newest entry - LogPrintf("CMasternodeBroadcast::Update -- Got UPDATED Masternode entry: addr=%s\n", addr.ToString()); - if(pmn->UpdateFromNewBroadcast(*this, connman)) { - pmn->Check(); - Relay(connman); - } - masternodeSync.BumpAssetLastTime("CMasternodeBroadcast::Update"); - } - - return true; -} - -bool CMasternodeBroadcast::CheckOutpoint(int& nDos) -{ - // we are a masternode with the same outpoint (i.e. already activated) and this mnb is ours (matches our Masternode privkey) - // so nothing to do here for us - if(fMasternodeMode && outpoint == activeMasternodeInfo.outpoint && legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator) { - return false; - } - - AssertLockHeld(cs_main); - - int nHeight; - CollateralStatus err = CheckCollateral(outpoint, keyIDCollateralAddress, nHeight); - if (err == COLLATERAL_UTXO_NOT_FOUND) { - LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Failed to find Masternode UTXO, masternode=%s\n", outpoint.ToStringShort()); - return false; - } - - if (err == COLLATERAL_INVALID_AMOUNT) { - LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should have 1000 DASH, masternode=%s\n", outpoint.ToStringShort()); - nDos = 33; - return false; - } - - if(err == COLLATERAL_INVALID_PUBKEY) { - LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should match keyIDCollateralAddress, masternode=%s\n", outpoint.ToStringShort()); - nDos = 33; - return false; - } - - if(chainActive.Height() - nHeight + 1 < Params().GetConsensus().nMasternodeMinimumConfirmations) { - LogPrintf("CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO must have at least %d confirmations, masternode=%s\n", - Params().GetConsensus().nMasternodeMinimumConfirmations, outpoint.ToStringShort()); - // UTXO is legit but has not enough confirmations. - // Maybe we miss few blocks, let this mnb be checked again later. - mnodeman.mapSeenMasternodeBroadcast.erase(GetHash()); - return false; - } - - LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO verified\n"); - - // Verify that sig time is legit, should be at least not earlier than the timestamp of the block - // at which collateral became nMasternodeMinimumConfirmations blocks deep. - // NOTE: this is not accurate because block timestamp is NOT guaranteed to be 100% correct one. - CBlockIndex* pRequiredConfIndex = chainActive[nHeight + Params().GetConsensus().nMasternodeMinimumConfirmations - 1]; // block where tx got nMasternodeMinimumConfirmations - if(pRequiredConfIndex->GetBlockTime() > sigTime) { - LogPrintf("CMasternodeBroadcast::CheckOutpoint -- Bad sigTime %d (%d conf block is at %d) for Masternode %s %s\n", - sigTime, Params().GetConsensus().nMasternodeMinimumConfirmations, pRequiredConfIndex->GetBlockTime(), outpoint.ToStringShort(), addr.ToString()); - return false; - } - - if (!CheckSignature(nDos)) { - LogPrintf("CMasternodeBroadcast::CheckOutpoint -- CheckSignature() failed, masternode=%s\n", outpoint.ToStringShort()); - return false; - } - - // remember the block hash when collateral for this masternode had minimum required confirmations - nCollateralMinConfBlockHash = pRequiredConfIndex->GetBlockHash(); - - return true; -} - -uint256 CMasternodeBroadcast::GetHash() const -{ - // Note: doesn't match serialization - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << outpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format - ss << pubKeyCollateralAddress; - ss << sigTime; - return ss.GetHash(); -} - -uint256 CMasternodeBroadcast::GetSignatureHash() const -{ - // TODO: replace with "return SerializeHash(*this);" after migration to 70209 - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << outpoint; - ss << addr; - ss << pubKeyCollateralAddress; - ss << pubKeyMasternode; - ss << sigTime; - ss << nProtocolVersion; - return ss.GetHash(); -} - -bool CMasternodeBroadcast::Sign(const CKey& keyCollateralAddress) -{ - std::string strError; - - sigTime = GetAdjustedTime(); - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::SignHash(hash, keyCollateralAddress, vchSig)) { - LogPrintf("CMasternodeBroadcast::Sign -- SignHash() failed\n"); - return false; - } - - if (!CHashSigner::VerifyHash(hash, keyIDCollateralAddress, vchSig, strError)) { - LogPrintf("CMasternodeBroadcast::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = addr.ToString(false) + std::to_string(sigTime) + - keyIDCollateralAddress.ToString() + legacyKeyIDOperator.ToString() + - std::to_string(nProtocolVersion); - - if (!CMessageSigner::SignMessage(strMessage, vchSig, keyCollateralAddress)) { - LogPrintf("CMasternodeBroadcast::Sign -- SignMessage() failed\n"); - return false; - } - - if(!CMessageSigner::VerifyMessage(keyIDCollateralAddress, vchSig, strMessage, strError)) { - LogPrintf("CMasternodeBroadcast::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } - - return true; -} - -bool CMasternodeBroadcast::CheckSignature(int& nDos) const -{ - std::string strError = ""; - nDos = 0; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, keyIDCollateralAddress, vchSig, strError)) { - // maybe it's in old format - std::string strMessage = addr.ToString(false) + std::to_string(sigTime) + - keyIDCollateralAddress.ToString() + legacyKeyIDOperator.ToString() + - std::to_string(nProtocolVersion); - - if (!CMessageSigner::VerifyMessage(keyIDCollateralAddress, vchSig, strMessage, strError)){ - // nope, not in old format either - LogPrintf("CMasternodeBroadcast::CheckSignature -- Got bad Masternode announce signature, error: %s\n", strError); - nDos = 100; - return false; - } - } - } else { - std::string strMessage = addr.ToString(false) + std::to_string(sigTime) + - keyIDCollateralAddress.ToString() + legacyKeyIDOperator.ToString() + - std::to_string(nProtocolVersion); - - if(!CMessageSigner::VerifyMessage(keyIDCollateralAddress, vchSig, strMessage, strError)){ - LogPrintf("CMasternodeBroadcast::CheckSignature -- Got bad Masternode announce signature, error: %s\n", strError); - nDos = 100; - return false; - } - } - - return true; -} - -void CMasternodeBroadcast::Relay(CConnman& connman) const -{ - // Do not relay until fully synced - if(!masternodeSync.IsSynced()) { - LogPrint("masternode", "CMasternodeBroadcast::Relay -- won't relay until fully synced\n"); - return; - } - - CInv inv(MSG_MASTERNODE_ANNOUNCE, GetHash()); - connman.RelayInv(inv); -} - -uint256 CMasternodePing::GetHash() const -{ - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - // TODO: replace with "return SerializeHash(*this);" after migration to 70209 - ss << masternodeOutpoint; - ss << blockHash; - ss << sigTime; - ss << fSentinelIsCurrent; - ss << nSentinelVersion; - ss << nDaemonVersion; - } else { - // Note: doesn't match serialization - - ss << masternodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format - ss << sigTime; - } - return ss.GetHash(); -} - -uint256 CMasternodePing::GetSignatureHash() const -{ - return GetHash(); -} - -CMasternodePing::CMasternodePing(const COutPoint& outpoint) -{ - LOCK(cs_main); - if (!chainActive.Tip() || chainActive.Height() < 12) return; - - masternodeOutpoint = outpoint; - blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash(); - sigTime = GetAdjustedTime(); - nDaemonVersion = CLIENT_VERSION; -} - -bool CMasternodePing::Sign(const CKey& keyMasternode, const CKeyID& keyIDOperator) -{ - std::string strError; - - sigTime = GetAdjustedTime(); - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::SignHash(hash, keyMasternode, vchSig)) { - LogPrintf("CMasternodePing::Sign -- SignHash() failed\n"); - return false; - } - - if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) { - LogPrintf("CMasternodePing::Sign -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + - std::to_string(sigTime); - - if (!CMessageSigner::SignMessage(strMessage, vchSig, keyMasternode)) { - LogPrintf("CMasternodePing::Sign -- SignMessage() failed\n"); - return false; - } - - if(!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CMasternodePing::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } - - return true; -} - -bool CMasternodePing::CheckSignature(CKeyID& keyIDOperator, int &nDos) const -{ - std::string strError = ""; - nDos = 0; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) { - std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + - std::to_string(sigTime); - - if(!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError); - nDos = 33; - return false; - } - } - } else { - std::string strMessage = CTxIn(masternodeOutpoint).ToString() + blockHash.ToString() + - std::to_string(sigTime); - - if (!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s\n", masternodeOutpoint.ToStringShort(), strError); - nDos = 33; - return false; - } - } - - return true; -} - -bool CMasternodePing::SimpleCheck(int& nDos) -{ - // don't ban by default - nDos = 0; - - if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("CMasternodePing::SimpleCheck -- Signature rejected, too far into the future, masternode=%s\n", masternodeOutpoint.ToStringShort()); - nDos = 1; - return false; - } - - { - AssertLockHeld(cs_main); - BlockMap::iterator mi = mapBlockIndex.find(blockHash); - if (mi == mapBlockIndex.end()) { - LogPrint("masternode", "CMasternodePing::SimpleCheck -- Masternode ping is invalid, unknown block hash: masternode=%s blockHash=%s\n", masternodeOutpoint.ToStringShort(), blockHash.ToString()); - // maybe we stuck or forked so we shouldn't ban this node, just fail to accept this ping - // TODO: or should we also request this block? - return false; - } - } - - LogPrint("masternode", "CMasternodePing::SimpleCheck -- Masternode ping verified: masternode=%s blockHash=%s sigTime=%d\n", masternodeOutpoint.ToStringShort(), blockHash.ToString(), sigTime); - return true; -} - -bool CMasternodePing::CheckAndUpdate(CMasternode* pmn, bool fFromNewBroadcast, int& nDos, CConnman& connman) -{ - AssertLockHeld(cs_main); - - // don't ban by default - nDos = 0; - - if (!SimpleCheck(nDos)) { - return false; - } - - if (pmn == nullptr) { - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- Couldn't find Masternode entry, masternode=%s\n", masternodeOutpoint.ToStringShort()); - return false; - } - - if(!fFromNewBroadcast) { - if (pmn->IsUpdateRequired()) { - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- masternode protocol is outdated, masternode=%s\n", masternodeOutpoint.ToStringShort()); - return false; - } - - if (pmn->IsNewStartRequired()) { - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- masternode is completely expired, new start is required, masternode=%s\n", masternodeOutpoint.ToStringShort()); - return false; - } - } - - { - BlockMap::iterator mi = mapBlockIndex.find(blockHash); - if ((*mi).second && (*mi).second->nHeight < chainActive.Height() - 24) { - LogPrintf("CMasternodePing::CheckAndUpdate -- Masternode ping is invalid, block hash is too old: masternode=%s blockHash=%s\n", masternodeOutpoint.ToStringShort(), blockHash.ToString()); - // nDos = 1; - return false; - } - } - - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- New ping: masternode=%s blockHash=%s sigTime=%d\n", masternodeOutpoint.ToStringShort(), blockHash.ToString(), sigTime); - - // LogPrintf("mnping - Found corresponding mn for outpoint: %s\n", masternodeOutpoint.ToStringShort()); - // update only if there is no known ping for this masternode or - // last ping was more then MASTERNODE_MIN_MNP_SECONDS-60 ago comparing to this one - if (pmn->IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS - 60, sigTime)) { - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- Masternode ping arrived too early, masternode=%s\n", masternodeOutpoint.ToStringShort()); - //nDos = 1; //disable, this is happening frequently and causing banned peers - return false; - } - - if (!CheckSignature(pmn->legacyKeyIDOperator, nDos)) return false; - - // so, ping seems to be ok - - // if we are still syncing and there was no known ping for this mn for quite a while - // (NOTE: assuming that MASTERNODE_EXPIRATION_SECONDS/2 should be enough to finish mn list sync) - if(!masternodeSync.IsMasternodeListSynced() && !pmn->IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS/2)) { - // let's bump sync timeout - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- bumping sync timeout, masternode=%s\n", masternodeOutpoint.ToStringShort()); - masternodeSync.BumpAssetLastTime("CMasternodePing::CheckAndUpdate"); - } - - // let's store this ping as the last one - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- Masternode ping accepted, masternode=%s\n", masternodeOutpoint.ToStringShort()); - pmn->lastPing = *this; - - // and update mnodeman.mapSeenMasternodeBroadcast.lastPing which is probably outdated - CMasternodeBroadcast mnb(*pmn); - uint256 hash = mnb.GetHash(); - if (mnodeman.mapSeenMasternodeBroadcast.count(hash)) { - mnodeman.mapSeenMasternodeBroadcast[hash].second.lastPing = *this; - } - - // force update, ignoring cache - pmn->Check(true); - // relay ping for nodes in ENABLED/EXPIRED/SENTINEL_PING_EXPIRED state only, skip everyone else - if (!pmn->IsEnabled() && !pmn->IsExpired() && !pmn->IsSentinelPingExpired()) return false; - - LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- Masternode ping acceepted and relayed, masternode=%s\n", masternodeOutpoint.ToStringShort()); - Relay(connman); - - return true; -} - -void CMasternodePing::Relay(CConnman& connman) -{ - // Do not relay until fully synced - if(!masternodeSync.IsSynced()) { - LogPrint("masternode", "CMasternodePing::Relay -- won't relay until fully synced\n"); - return; - } - - CInv inv(MSG_MASTERNODE_PING, GetHash()); - connman.RelayInv(inv); -} - -std::string CMasternodePing::GetSentinelString() const -{ - return nSentinelVersion > DEFAULT_SENTINEL_VERSION ? SafeIntVersionToString(nSentinelVersion) : "Unknown"; -} - -std::string CMasternodePing::GetDaemonString() const -{ - return nDaemonVersion > DEFAULT_DAEMON_VERSION ? FormatVersion(nDaemonVersion) : "Unknown"; -} - void CMasternode::AddGovernanceVote(uint256 nGovernanceObjectHash) { // Insert a zero value, or not. Then increment the value regardless. This diff --git a/src/masternode.h b/src/masternode.h index 81e396d07e..fbfc434d11 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -13,89 +13,10 @@ #include "evo/deterministicmns.h" class CMasternode; -class CMasternodeBroadcast; class CConnman; -static const int MASTERNODE_CHECK_SECONDS = 5; -static const int MASTERNODE_MIN_MNB_SECONDS = 5 * 60; -static const int MASTERNODE_MIN_MNP_SECONDS = 10 * 60; -static const int MASTERNODE_SENTINEL_PING_MAX_SECONDS = 60 * 60; -static const int MASTERNODE_EXPIRATION_SECONDS = 120 * 60; -static const int MASTERNODE_NEW_START_REQUIRED_SECONDS = 180 * 60; - -static const int MASTERNODE_POSE_BAN_MAX_SCORE = 5; static const int MASTERNODE_MAX_MIXING_TXES = 5; -// -// The Masternode Ping Class : Contains a different serialize method for sending pings from masternodes throughout the network -// - -// sentinel version before implementation of nSentinelVersion in CMasternodePing -#define DEFAULT_SENTINEL_VERSION 0x010001 -// daemon version before implementation of nDaemonVersion in CMasternodePing -#define DEFAULT_DAEMON_VERSION 120200 - -class CMasternodePing -{ -public: - COutPoint masternodeOutpoint{}; - uint256 blockHash{}; - int64_t sigTime{}; //mnb message times - std::vector vchSig{}; - bool fSentinelIsCurrent = false; // true if last sentinel ping was current - // MSB is always 0, other 3 bits corresponds to x.x.x version scheme - uint32_t nSentinelVersion{DEFAULT_SENTINEL_VERSION}; - uint32_t nDaemonVersion{DEFAULT_DAEMON_VERSION}; - - CMasternodePing() = default; - - CMasternodePing(const COutPoint& outpoint); - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(masternodeOutpoint); - READWRITE(blockHash); - READWRITE(sigTime); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(vchSig); - } - READWRITE(fSentinelIsCurrent); - READWRITE(nSentinelVersion); - READWRITE(nDaemonVersion); - } - - uint256 GetHash() const; - uint256 GetSignatureHash() const; - - bool IsExpired() const { return GetAdjustedTime() - sigTime > MASTERNODE_NEW_START_REQUIRED_SECONDS; } - - bool Sign(const CKey& keyMasternode, const CKeyID& keyIDOperator); - bool CheckSignature(CKeyID& keyIDOperator, int &nDos) const; - bool SimpleCheck(int& nDos); - bool CheckAndUpdate(CMasternode* pmn, bool fFromNewBroadcast, int& nDos, CConnman& connman); - void Relay(CConnman& connman); - - std::string GetSentinelString() const; - std::string GetDaemonString() const; - - explicit operator bool() const; -}; - -inline bool operator==(const CMasternodePing& a, const CMasternodePing& b) -{ - return a.masternodeOutpoint == b.masternodeOutpoint && a.blockHash == b.blockHash; -} -inline bool operator!=(const CMasternodePing& a, const CMasternodePing& b) -{ - return !(a == b); -} -inline CMasternodePing::operator bool() const -{ - return *this != CMasternodePing(); -} - struct masternode_info_t { // Note: all these constructors can be removed once C++14 is enabled. @@ -103,43 +24,14 @@ struct masternode_info_t masternode_info_t() = default; masternode_info_t(masternode_info_t const&) = default; - masternode_info_t(int activeState, int protoVer, int64_t sTime) : - nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime} {} - // only called when the network is in legacy MN list mode - masternode_info_t(int activeState, int protoVer, int64_t sTime, - COutPoint const& outpnt, CService const& addr, - CPubKey const& pkCollAddr, CPubKey const& pkMN) : - nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime}, - outpoint{outpnt}, addr{addr}, - pubKeyCollateralAddress{pkCollAddr}, pubKeyMasternode{pkMN}, keyIDCollateralAddress{pkCollAddr.GetID()}, keyIDOwner{pkMN.GetID()}, legacyKeyIDOperator{pkMN.GetID()}, keyIDVoting{pkMN.GetID()} {} - - // only called when the network is in deterministic MN list mode - masternode_info_t(int activeState, int protoVer, int64_t sTime, - COutPoint const& outpnt, CService const& addr, - CKeyID const& pkCollAddr, CKeyID const& pkOwner, CBLSPublicKey const& pkOperator, CKeyID const& pkVoting) : - nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime}, - outpoint{outpnt}, addr{addr}, - pubKeyCollateralAddress{}, pubKeyMasternode{}, keyIDCollateralAddress{pkCollAddr}, keyIDOwner{pkOwner}, blsPubKeyOperator{pkOperator}, keyIDVoting{pkVoting} {} - - int nActiveState = 0; - int nProtocolVersion = 0; - int64_t sigTime = 0; //mnb message time + masternode_info_t(COutPoint const& outpnt) : + outpoint{outpnt} + {} COutPoint outpoint{}; - CService addr{}; - CPubKey pubKeyCollateralAddress{}; // this will be invalid/unset when the network switches to deterministic MNs (luckely it's only important for the broadcast hash) - CPubKey pubKeyMasternode{}; // this will be invalid/unset when the network switches to deterministic MNs (luckely it's only important for the broadcast hash) - CKeyID keyIDCollateralAddress{}; // this is only used in compatibility code and won't be used when spork15 gets activated - CKeyID keyIDOwner{}; - CKeyID legacyKeyIDOperator{}; - CBLSPublicKey blsPubKeyOperator; - CKeyID keyIDVoting{}; int64_t nLastDsq = 0; //the dsq count from the last dsq broadcast of this node - int64_t nTimeLastChecked = 0; - int64_t nTimeLastPaid = 0; - int64_t nTimeLastPing = 0; //* not in CMN bool fInfoValid = false; //* not in CMN }; @@ -154,42 +46,13 @@ private: mutable CCriticalSection cs; public: - enum state { - MASTERNODE_PRE_ENABLED, - MASTERNODE_ENABLED, - MASTERNODE_EXPIRED, - MASTERNODE_OUTPOINT_SPENT, - MASTERNODE_UPDATE_REQUIRED, - MASTERNODE_SENTINEL_PING_EXPIRED, - MASTERNODE_NEW_START_REQUIRED, - MASTERNODE_POSE_BAN - }; - - enum CollateralStatus { - COLLATERAL_OK, - COLLATERAL_UTXO_NOT_FOUND, - COLLATERAL_INVALID_AMOUNT, - COLLATERAL_INVALID_PUBKEY, - }; - - - CMasternodePing lastPing{}; - std::vector vchSig{}; - - uint256 nCollateralMinConfBlockHash{}; - int nBlockLastPaid{}; - int nPoSeBanScore{}; - int nPoSeBanHeight{}; int nMixingTxCount{}; - bool fUnitTest = false; // KEEP TRACK OF GOVERNANCE ITEMS EACH MASTERNODE HAS VOTE UPON FOR RECALCULATION std::map mapGovernanceObjectsVotedOn; CMasternode(); CMasternode(const CMasternode& other); - CMasternode(const CMasternodeBroadcast& mnb); - CMasternode(CService addrNew, COutPoint outpointNew, CPubKey pubKeyCollateralAddressNew, CPubKey pubKeyMasternodeNew, int nProtocolVersionIn); CMasternode(const uint256 &proTxHash, const CDeterministicMNCPtr& dmn); ADD_SERIALIZE_METHODS; @@ -198,106 +61,18 @@ public: inline void SerializationOp(Stream& s, Operation ser_action) { LOCK(cs); READWRITE(outpoint); - READWRITE(addr); - READWRITE(pubKeyCollateralAddress); - READWRITE(pubKeyMasternode); - READWRITE(keyIDCollateralAddress); - READWRITE(keyIDOwner); - READWRITE(legacyKeyIDOperator); - READWRITE(blsPubKeyOperator); - READWRITE(keyIDVoting); - READWRITE(lastPing); - READWRITE(vchSig); - READWRITE(sigTime); READWRITE(nLastDsq); - READWRITE(nTimeLastChecked); - READWRITE(nTimeLastPaid); - READWRITE(nActiveState); - READWRITE(nCollateralMinConfBlockHash); - READWRITE(nBlockLastPaid); - READWRITE(nProtocolVersion); - READWRITE(nPoSeBanScore); - READWRITE(nPoSeBanHeight); READWRITE(nMixingTxCount); - READWRITE(fUnitTest); READWRITE(mapGovernanceObjectsVotedOn); } - // CALCULATE A RANK AGAINST OF GIVEN BLOCK - arith_uint256 CalculateScore(const uint256& blockHash) const; - - bool UpdateFromNewBroadcast(CMasternodeBroadcast& mnb, CConnman& connman); - - static CollateralStatus CheckCollateral(const COutPoint& outpoint, const CKeyID& keyID); - static CollateralStatus CheckCollateral(const COutPoint& outpoint, const CKeyID& keyID, int& nHeightRet); - void Check(bool fForce = false); - - bool IsBroadcastedWithin(int nSeconds) { return GetAdjustedTime() - sigTime < nSeconds; } - - bool IsPingedWithin(int nSeconds, int64_t nTimeToCheckAt = -1) - { - if(!lastPing) return false; - - if(nTimeToCheckAt == -1) { - nTimeToCheckAt = GetAdjustedTime(); - } - return nTimeToCheckAt - lastPing.sigTime < nSeconds; - } - - bool IsEnabled() const { return nActiveState == MASTERNODE_ENABLED; } - bool IsPreEnabled() const { return nActiveState == MASTERNODE_PRE_ENABLED; } - bool IsPoSeBanned() const { return nActiveState == MASTERNODE_POSE_BAN; } - // NOTE: this one relies on nPoSeBanScore, not on nActiveState as everything else here - bool IsPoSeVerified() const { return nPoSeBanScore <= -MASTERNODE_POSE_BAN_MAX_SCORE; } - bool IsExpired() const { return nActiveState == MASTERNODE_EXPIRED; } - bool IsOutpointSpent() const { return nActiveState == MASTERNODE_OUTPOINT_SPENT; } - bool IsUpdateRequired() const { return nActiveState == MASTERNODE_UPDATE_REQUIRED; } - bool IsSentinelPingExpired() const { return nActiveState == MASTERNODE_SENTINEL_PING_EXPIRED; } - bool IsNewStartRequired() const { return nActiveState == MASTERNODE_NEW_START_REQUIRED; } - - static bool IsValidStateForAutoStart(int nActiveStateIn) - { - return nActiveStateIn == MASTERNODE_ENABLED || - nActiveStateIn == MASTERNODE_PRE_ENABLED || - nActiveStateIn == MASTERNODE_EXPIRED || - nActiveStateIn == MASTERNODE_SENTINEL_PING_EXPIRED; - } - - bool IsValidForPayment() const - { - if(nActiveState == MASTERNODE_ENABLED) { - return true; - } - if(!sporkManager.IsSporkActive(SPORK_14_REQUIRE_SENTINEL_FLAG) && - (nActiveState == MASTERNODE_SENTINEL_PING_EXPIRED)) { - return true; - } - - return false; - } - bool IsValidForMixingTxes() const { return nMixingTxCount <= MASTERNODE_MAX_MIXING_TXES; } - bool IsValidNetAddr(); - static bool IsValidNetAddr(CService addrIn); - - void IncreasePoSeBanScore() { if(nPoSeBanScore < MASTERNODE_POSE_BAN_MAX_SCORE) nPoSeBanScore++; } - void DecreasePoSeBanScore() { if(nPoSeBanScore > -MASTERNODE_POSE_BAN_MAX_SCORE) nPoSeBanScore--; } - void PoSeBan() { nPoSeBanScore = MASTERNODE_POSE_BAN_MAX_SCORE; } - masternode_info_t GetInfo() const; - static std::string StateToString(int nStateIn); - std::string GetStateString() const; - std::string GetStatus() const; - - int GetLastPaidTime() const { return nTimeLastPaid; } - int GetLastPaidBlock() const { return nBlockLastPaid; } - void UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack); - // KEEP TRACK OF EACH GOVERNANCE ITEM INCASE THIS NODE GOES OFFLINE, SO WE CAN RECALC THEIR STATUS void AddGovernanceVote(uint256 nGovernanceObjectHash); // RECALCULATE CACHED STATUS FLAGS FOR ALL AFFECTED OBJECTS @@ -308,14 +83,7 @@ public: CMasternode& operator=(CMasternode const& from) { static_cast(*this)=from; - lastPing = from.lastPing; - vchSig = from.vchSig; - nCollateralMinConfBlockHash = from.nCollateralMinConfBlockHash; - nBlockLastPaid = from.nBlockLastPaid; - nPoSeBanScore = from.nPoSeBanScore; - nPoSeBanHeight = from.nPoSeBanHeight; nMixingTxCount = from.nMixingTxCount; - fUnitTest = from.fUnitTest; mapGovernanceObjectsVotedOn = from.mapGovernanceObjectsVotedOn; return *this; } @@ -330,138 +98,4 @@ inline bool operator!=(const CMasternode& a, const CMasternode& b) return !(a.outpoint == b.outpoint); } - -// -// The Masternode Broadcast Class : Contains a different serialize method for sending masternodes through the network -// - -class CMasternodeBroadcast : public CMasternode -{ -public: - - bool fRecovery; - - CMasternodeBroadcast() : CMasternode(), fRecovery(false) {} - CMasternodeBroadcast(const CMasternode& mn) : CMasternode(mn), fRecovery(false) {} - CMasternodeBroadcast(CService addrNew, COutPoint outpointNew, CPubKey pubKeyCollateralAddressNew, CPubKey pubKeyMasternodeNew, int nProtocolVersionIn) : - CMasternode(addrNew, outpointNew, pubKeyCollateralAddressNew, pubKeyMasternodeNew, nProtocolVersionIn), fRecovery(false) {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(outpoint); - READWRITE(addr); - READWRITE(pubKeyCollateralAddress); - READWRITE(pubKeyMasternode); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(vchSig); - } - READWRITE(sigTime); - READWRITE(nProtocolVersion); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(lastPing); - } - - if (ser_action.ForRead()) { - keyIDCollateralAddress = pubKeyCollateralAddress.GetID(); - keyIDOwner = pubKeyMasternode.GetID(); - legacyKeyIDOperator = pubKeyMasternode.GetID(); - keyIDVoting = pubKeyMasternode.GetID(); - } - } - - uint256 GetHash() const; - uint256 GetSignatureHash() const; - - /// Create Masternode broadcast, needs to be relayed manually after that - static bool Create(const COutPoint& outpoint, const CService& service, const CKey& keyCollateralAddressNew, const CPubKey& pubKeyCollateralAddressNew, const CKey& keyMasternodeNew, const CPubKey& pubKeyMasternodeNew, std::string &strErrorRet, CMasternodeBroadcast &mnbRet); - static bool Create(const std::string& strService, const std::string& strKey, const std::string& strTxHash, const std::string& strOutputIndex, std::string& strErrorRet, CMasternodeBroadcast &mnbRet, bool fOffline = false); - - bool SimpleCheck(int& nDos); - bool Update(CMasternode* pmn, int& nDos, CConnman& connman); - bool CheckOutpoint(int& nDos); - - bool Sign(const CKey& keyCollateralAddress); - bool CheckSignature(int& nDos) const; - void Relay(CConnman& connman) const; -}; - -class CMasternodeVerification -{ -public: - COutPoint masternodeOutpoint1{}; - COutPoint masternodeOutpoint2{}; - CService addr{}; - int nonce{}; - int nBlockHeight{}; - std::vector vchSig1{}; - std::vector vchSig2{}; - - CMasternodeVerification() = default; - - CMasternodeVerification(CService addr, int nonce, int nBlockHeight) : - addr(addr), - nonce(nonce), - nBlockHeight(nBlockHeight) - {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(masternodeOutpoint1); - READWRITE(masternodeOutpoint2); - READWRITE(addr); - READWRITE(nonce); - READWRITE(nBlockHeight); - READWRITE(vchSig1); - READWRITE(vchSig2); - } - - uint256 GetHash() const - { - // Note: doesn't match serialization - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - // adding dummy values here to match old hashing format - ss << masternodeOutpoint1 << uint8_t{} << 0xffffffff; - ss << masternodeOutpoint2 << uint8_t{} << 0xffffffff; - ss << addr; - ss << nonce; - ss << nBlockHeight; - return ss.GetHash(); - } - - uint256 GetSignatureHash1(const uint256& blockHash) const - { - // Note: doesn't match serialization - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << addr; - ss << nonce; - ss << blockHash; - return ss.GetHash(); - } - - uint256 GetSignatureHash2(const uint256& blockHash) const - { - // Note: doesn't match serialization - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << masternodeOutpoint1; - ss << masternodeOutpoint2; - ss << addr; - ss << nonce; - ss << blockHash; - return ss.GetHash(); - } - - void Relay() const - { - CInv inv(MSG_MASTERNODE_VERIFY, GetHash()); - g_connman->RelayInv(inv); - } -}; - #endif diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp deleted file mode 100644 index 0e2e67be79..0000000000 --- a/src/masternodeconfig.cpp +++ /dev/null @@ -1,91 +0,0 @@ - -#include "netbase.h" -#include "masternodeconfig.h" -#include "util.h" -#include "chainparams.h" - -#include -#include - -CMasternodeConfig masternodeConfig; - -void CMasternodeConfig::add(const std::string& alias, const std::string& ip, const std::string& privKey, const std::string& txHash, const std::string& outputIndex) { - CMasternodeEntry cme(alias, ip, privKey, txHash, outputIndex); - entries.push_back(cme); -} - -bool CMasternodeConfig::read(std::string& strErrRet) { - int linenumber = 1; - boost::filesystem::path pathMasternodeConfigFile = GetMasternodeConfigFile(); - boost::filesystem::ifstream streamConfig(pathMasternodeConfigFile); - - if (!streamConfig.good()) { - FILE* configFile = fopen(pathMasternodeConfigFile.string().c_str(), "a"); - if (configFile != nullptr) { - std::string strHeader = "# Masternode config file\n" - "# Format: alias IP:port masternodeprivkey collateral_output_txid collateral_output_index\n" - "# Example: mn1 127.0.0.2:19999 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0\n"; - fwrite(strHeader.c_str(), std::strlen(strHeader.c_str()), 1, configFile); - fclose(configFile); - } - return true; // Nothing to read, so just return - } - - for(std::string line; std::getline(streamConfig, line); linenumber++) - { - if(line.empty()) continue; - - std::istringstream iss(line); - std::string comment, alias, ip, privKey, txHash, outputIndex; - - if (iss >> comment) { - if(comment.at(0) == '#') continue; - iss.str(line); - iss.clear(); - } - - if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { - iss.str(line); - iss.clear(); - if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { - strErrRet = _("Could not parse masternode.conf") + "\n" + - strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\""; - streamConfig.close(); - return false; - } - } - - int port = 0; - std::string hostname = ""; - SplitHostPort(ip, port, hostname); - if(port == 0 || hostname == "") { - strErrRet = _("Failed to parse host:port string") + "\n"+ - strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\""; - streamConfig.close(); - return false; - } - int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort(); - if(Params().NetworkIDString() == CBaseChainParams::MAIN) { - if(port != mainnetDefaultPort) { - strErrRet = _("Invalid port detected in masternode.conf") + "\n" + - strprintf(_("Port: %d"), port) + "\n" + - strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\"" + "\n" + - strprintf(_("(must be %d for mainnet)"), mainnetDefaultPort); - streamConfig.close(); - return false; - } - } else if(port == mainnetDefaultPort) { - strErrRet = _("Invalid port detected in masternode.conf") + "\n" + - strprintf(_("Line: %d"), linenumber) + "\n\"" + line + "\"" + "\n" + - strprintf(_("(%d could be used only on mainnet)"), mainnetDefaultPort); - streamConfig.close(); - return false; - } - - - add(alias, ip, privKey, txHash, outputIndex); - } - - streamConfig.close(); - return true; -} diff --git a/src/masternodeconfig.h b/src/masternodeconfig.h deleted file mode 100644 index 7d978d9dc7..0000000000 --- a/src/masternodeconfig.h +++ /dev/null @@ -1,79 +0,0 @@ - -// Copyright (c) 2014-2017 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. - -#ifndef SRC_MASTERNODECONFIG_H_ -#define SRC_MASTERNODECONFIG_H_ - -class CMasternodeConfig; -extern CMasternodeConfig masternodeConfig; - -class CMasternodeConfig -{ - -public: - - class CMasternodeEntry { - - private: - std::string alias; - std::string ip; - std::string privKey; - std::string txHash; - std::string outputIndex; - public: - - CMasternodeEntry(const std::string& alias, const std::string& ip, const std::string& privKey, const std::string& txHash, const std::string& outputIndex) { - this->alias = alias; - this->ip = ip; - this->privKey = privKey; - this->txHash = txHash; - this->outputIndex = outputIndex; - } - - const std::string& getAlias() const { - return alias; - } - - const std::string& getOutputIndex() const { - return outputIndex; - } - - const std::string& getPrivKey() const { - return privKey; - } - - const std::string& getTxHash() const { - return txHash; - } - - const std::string& getIp() const { - return ip; - } - }; - - CMasternodeConfig() { - entries = std::vector(); - } - - void clear(); - bool read(std::string& strErrRet); - void add(const std::string& alias, const std::string& ip, const std::string& privKey, const std::string& txHash, const std::string& outputIndex); - - std::vector& getEntries() { - return entries; - } - - int getCount() { - return (int)entries.size(); - } - -private: - std::vector entries; - - -}; - - -#endif /* SRC_MASTERNODECONFIG_H_ */ diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 8ef74f5cf1..9e9581d583 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -28,17 +28,7 @@ /** Masternode manager */ CMasternodeMan mnodeman; -const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-12"; -const int CMasternodeMan::LAST_PAID_SCAN_BLOCKS = 100; - -struct CompareLastPaidBlock -{ - bool operator()(const std::pair& t1, - const std::pair& t2) const - { - return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->outpoint < t2.second->outpoint); - } -}; +const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-13"; struct CompareScoreMN { @@ -49,84 +39,13 @@ struct CompareScoreMN } }; -struct CompareByAddr - -{ - bool operator()(const CMasternode* t1, - const CMasternode* t2) const - { - return t1->addr < t2->addr; - } -}; - CMasternodeMan::CMasternodeMan(): cs(), mapMasternodes(), - mAskedUsForMasternodeList(), - mWeAskedForMasternodeList(), - mWeAskedForMasternodeListEntry(), - mWeAskedForVerification(), - mMnbRecoveryRequests(), - mMnbRecoveryGoodReplies(), - listScheduledMnbRequestConnections(), - fMasternodesAdded(false), - fMasternodesRemoved(false), vecDirtyGovernanceObjectHashes(), - nLastSentinelPingTime(0), - mapSeenMasternodeBroadcast(), - mapSeenMasternodePing(), nDsqCount(0) {} -bool CMasternodeMan::Add(CMasternode &mn) -{ - LOCK(cs); - - if (deterministicMNManager->IsDIP3Active()) - return false; - - if (Has(mn.outpoint)) return false; - - LogPrint("masternode", "CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now\n", mn.addr.ToString(), size() + 1); - mapMasternodes[mn.outpoint] = mn; - fMasternodesAdded = true; - return true; -} - -void CMasternodeMan::AskForMN(CNode* pnode, const COutPoint& outpoint, CConnman& connman) -{ - if(!pnode) return; - - CNetMsgMaker msgMaker(pnode->GetSendVersion()); - LOCK(cs); - - if (deterministicMNManager->IsDIP3Active()) - return; - - CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0); - auto it1 = mWeAskedForMasternodeListEntry.find(outpoint); - if (it1 != mWeAskedForMasternodeListEntry.end()) { - auto it2 = it1->second.find(addrSquashed); - if (it2 != it1->second.end()) { - if (GetTime() < it2->second) { - // we've asked recently, should not repeat too often or we could get banned - return; - } - // we asked this node for this outpoint but it's ok to ask again already - LogPrintf("CMasternodeMan::AskForMN -- Asking same peer %s for missing masternode entry again: %s\n", addrSquashed.ToString(), outpoint.ToStringShort()); - } else { - // we already asked for this outpoint but not this node - LogPrintf("CMasternodeMan::AskForMN -- Asking new peer %s for missing masternode entry: %s\n", addrSquashed.ToString(), outpoint.ToStringShort()); - } - } else { - // we never asked any node for this outpoint - LogPrintf("CMasternodeMan::AskForMN -- Asking peer %s for missing masternode entry for the first time: %s\n", addrSquashed.ToString(), outpoint.ToStringShort()); - } - mWeAskedForMasternodeListEntry[outpoint][addrSquashed] = GetTime() + DSEG_UPDATE_SECONDS; - - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSEG, outpoint)); -} - bool CMasternodeMan::IsValidForMixingTxes(const COutPoint& outpoint) { LOCK(cs); @@ -173,596 +92,37 @@ int64_t CMasternodeMan::GetLastDsq(const COutPoint& outpoint) return pmn->nLastDsq; } -bool CMasternodeMan::PoSeBan(const COutPoint &outpoint) -{ - LOCK(cs); - - if (deterministicMNManager->IsDIP3Active()) - return true; - - CMasternode* pmn = Find(outpoint); - if (!pmn) { - return false; - } - pmn->PoSeBan(); - - return true; -} - -void CMasternodeMan::Check() -{ - LOCK2(cs_main, cs); - - if (deterministicMNManager->IsDIP3Active()) - return; - - for (auto& mnpair : mapMasternodes) { - // NOTE: internally it checks only every MASTERNODE_CHECK_SECONDS seconds - // since the last time, so expect some MNs to skip this - mnpair.second.Check(); - } -} - -void CMasternodeMan::CheckAndRemove(CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) - return; - - if(!masternodeSync.IsMasternodeListSynced()) return; - - LogPrintf("CMasternodeMan::CheckAndRemove\n"); - - { - // Need LOCK2 here to ensure consistent locking order because code below locks cs_main - // in CheckMnbAndUpdateMasternodeList() - LOCK2(cs_main, cs); - - Check(); - - // Remove spent masternodes, prepare structures and make requests to reasure the state of inactive ones - rank_pair_vec_t vecMasternodeRanks; - // ask for up to MNB_RECOVERY_MAX_ASK_ENTRIES masternode entries at a time - int nAskForMnbRecovery = MNB_RECOVERY_MAX_ASK_ENTRIES; - std::map::iterator it = mapMasternodes.begin(); - while (it != mapMasternodes.end()) { - CMasternodeBroadcast mnb = CMasternodeBroadcast(it->second); - uint256 hash = mnb.GetHash(); - // If collateral was spent ... - if (it->second.IsOutpointSpent()) { - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing Masternode: %s addr=%s %i now\n", it->second.GetStateString(), it->second.addr.ToString(), size() - 1); - - // erase all of the broadcasts we've seen from this txin, ... - mapSeenMasternodeBroadcast.erase(hash); - mWeAskedForMasternodeListEntry.erase(it->first); - - // and finally remove it from the list - it->second.FlagGovernanceItemsAsDirty(); - mapMasternodes.erase(it++); - fMasternodesRemoved = true; - } else { - bool fAsk = (nAskForMnbRecovery > 0) && - masternodeSync.IsSynced() && - it->second.IsNewStartRequired() && - !IsMnbRecoveryRequested(hash) && - !IsArgSet("-connect"); - if(fAsk) { - // this mn is in a non-recoverable state and we haven't asked other nodes yet - std::set setRequested; - // calulate only once and only when it's needed - if(vecMasternodeRanks.empty()) { - int nRandomBlockHeight = GetRandInt(nCachedBlockHeight); - GetMasternodeRanks(vecMasternodeRanks, nRandomBlockHeight); - } - bool fAskedForMnbRecovery = false; - // ask first MNB_RECOVERY_QUORUM_TOTAL masternodes we can connect to and we haven't asked recently - for(int i = 0; setRequested.size() < MNB_RECOVERY_QUORUM_TOTAL && i < (int)vecMasternodeRanks.size(); i++) { - // avoid banning - if(mWeAskedForMasternodeListEntry.count(it->first) && mWeAskedForMasternodeListEntry[it->first].count(vecMasternodeRanks[i].second->pdmnState->addr)) continue; - // didn't ask recently, ok to ask now - CService addr = vecMasternodeRanks[i].second->pdmnState->addr; - setRequested.insert(addr); - listScheduledMnbRequestConnections.push_back(std::make_pair(addr, hash)); - fAskedForMnbRecovery = true; - } - if(fAskedForMnbRecovery) { - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Recovery initiated, masternode=%s\n", it->first.ToStringShort()); - nAskForMnbRecovery--; - } - // wait for mnb recovery replies for MNB_RECOVERY_WAIT_SECONDS seconds - mMnbRecoveryRequests[hash] = std::make_pair(GetTime() + MNB_RECOVERY_WAIT_SECONDS, setRequested); - } - ++it; - } - } - - // proces replies for MASTERNODE_NEW_START_REQUIRED masternodes - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- mMnbRecoveryGoodReplies size=%d\n", (int)mMnbRecoveryGoodReplies.size()); - std::map >::iterator itMnbReplies = mMnbRecoveryGoodReplies.begin(); - while(itMnbReplies != mMnbRecoveryGoodReplies.end()){ - if(mMnbRecoveryRequests[itMnbReplies->first].first < GetTime()) { - // all nodes we asked should have replied now - if(itMnbReplies->second.size() >= MNB_RECOVERY_QUORUM_REQUIRED) { - // majority of nodes we asked agrees that this mn doesn't require new mnb, reprocess one of new mnbs - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- reprocessing mnb, masternode=%s\n", itMnbReplies->second[0].outpoint.ToStringShort()); - // mapSeenMasternodeBroadcast.erase(itMnbReplies->first); - int nDos; - itMnbReplies->second[0].fRecovery = true; - CheckMnbAndUpdateMasternodeList(nullptr, itMnbReplies->second[0], nDos, connman); - } - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- removing mnb recovery reply, masternode=%s, size=%d\n", itMnbReplies->second[0].outpoint.ToStringShort(), (int)itMnbReplies->second.size()); - mMnbRecoveryGoodReplies.erase(itMnbReplies++); - } else { - ++itMnbReplies; - } - } - } - { - // no need for cm_main below - LOCK(cs); - - auto itMnbRequest = mMnbRecoveryRequests.begin(); - while(itMnbRequest != mMnbRecoveryRequests.end()){ - // Allow this mnb to be re-verified again after MNB_RECOVERY_RETRY_SECONDS seconds - // if mn is still in MASTERNODE_NEW_START_REQUIRED state. - if(GetTime() - itMnbRequest->second.first > MNB_RECOVERY_RETRY_SECONDS) { - mMnbRecoveryRequests.erase(itMnbRequest++); - } else { - ++itMnbRequest; - } - } - - // check who's asked for the Masternode list - auto it1 = mAskedUsForMasternodeList.begin(); - while(it1 != mAskedUsForMasternodeList.end()){ - if((*it1).second < GetTime()) { - mAskedUsForMasternodeList.erase(it1++); - } else { - ++it1; - } - } - - // check who we asked for the Masternode list - it1 = mWeAskedForMasternodeList.begin(); - while(it1 != mWeAskedForMasternodeList.end()){ - if((*it1).second < GetTime()){ - mWeAskedForMasternodeList.erase(it1++); - } else { - ++it1; - } - } - - // check which Masternodes we've asked for - auto it2 = mWeAskedForMasternodeListEntry.begin(); - while(it2 != mWeAskedForMasternodeListEntry.end()){ - auto it3 = it2->second.begin(); - while(it3 != it2->second.end()){ - if(it3->second < GetTime()){ - it2->second.erase(it3++); - } else { - ++it3; - } - } - if(it2->second.empty()) { - mWeAskedForMasternodeListEntry.erase(it2++); - } else { - ++it2; - } - } - - auto it3 = mWeAskedForVerification.begin(); - while(it3 != mWeAskedForVerification.end()){ - if(it3->second.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS) { - mWeAskedForVerification.erase(it3++); - } else { - ++it3; - } - } - - // NOTE: do not expire mapSeenMasternodeBroadcast entries here, clean them on mnb updates! - - // remove expired mapSeenMasternodePing - std::map::iterator it4 = mapSeenMasternodePing.begin(); - while(it4 != mapSeenMasternodePing.end()){ - if((*it4).second.IsExpired()) { - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode ping: hash=%s\n", (*it4).second.GetHash().ToString()); - mapSeenMasternodePing.erase(it4++); - } else { - ++it4; - } - } - - // remove expired mapSeenMasternodeVerification - std::map::iterator itv2 = mapSeenMasternodeVerification.begin(); - while(itv2 != mapSeenMasternodeVerification.end()){ - if((*itv2).second.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS){ - LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode verification: hash=%s\n", (*itv2).first.ToString()); - mapSeenMasternodeVerification.erase(itv2++); - } else { - ++itv2; - } - } - - LogPrintf("CMasternodeMan::CheckAndRemove -- %s\n", ToString()); - } - - if(fMasternodesRemoved) { - NotifyMasternodeUpdates(connman); - } -} - -void CMasternodeMan::AddDeterministicMasternodes() -{ - if (!deterministicMNManager->IsDIP3Active()) - return; - - bool added = false; - { - LOCK(cs); - unsigned int oldMnCount = mapMasternodes.size(); - - auto mnList = deterministicMNManager->GetListAtChainTip(); - mnList.ForEachMN(true, [this](const CDeterministicMNCPtr& dmn) { - // call Find() on each deterministic MN to force creation of CMasternode object - auto mn = Find(dmn->collateralOutpoint); - assert(mn); - - // make sure we use the splitted keys from now on - mn->keyIDOwner = dmn->pdmnState->keyIDOwner; - mn->blsPubKeyOperator = dmn->pdmnState->pubKeyOperator; - mn->keyIDVoting = dmn->pdmnState->keyIDVoting; - mn->addr = dmn->pdmnState->addr; - mn->nProtocolVersion = DMN_PROTO_VERSION; - - // If it appeared in the valid list, it is enabled no matter what - mn->nActiveState = CMasternode::MASTERNODE_ENABLED; - }); - - added = oldMnCount != mapMasternodes.size(); - } - - if (added) { - NotifyMasternodeUpdates(*g_connman, true, false); - } -} - -void CMasternodeMan::RemoveNonDeterministicMasternodes() -{ - if (!deterministicMNManager->IsDIP3Active()) - return; - - bool erased = false; - { - LOCK(cs); - std::set mnSet; - auto mnList = deterministicMNManager->GetListAtChainTip(); - mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) { - mnSet.insert(dmn->collateralOutpoint); - }); - auto it = mapMasternodes.begin(); - while (it != mapMasternodes.end()) { - if (!mnSet.count(it->second.outpoint)) { - mapMasternodes.erase(it++); - erased = true; - } else { - ++it; - } - } - } - if (erased) { - NotifyMasternodeUpdates(*g_connman, false, true); - } -} - void CMasternodeMan::Clear() { LOCK(cs); mapMasternodes.clear(); - mAskedUsForMasternodeList.clear(); - mWeAskedForMasternodeList.clear(); - mWeAskedForMasternodeListEntry.clear(); - mapSeenMasternodeBroadcast.clear(); - mapSeenMasternodePing.clear(); nDsqCount = 0; - nLastSentinelPingTime = 0; -} - -int CMasternodeMan::CountMasternodes(int nProtocolVersion) -{ - LOCK(cs); - - int nCount = 0; - nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion; - - if (deterministicMNManager->IsDIP3Active()) { - auto mnList = deterministicMNManager->GetListAtChainTip(); - nCount = (int)mnList.GetAllMNsCount(); - } else { - for (const auto& mnpair : mapMasternodes) { - if(mnpair.second.nProtocolVersion < nProtocolVersion) continue; - nCount++; - } - } - return nCount; -} - -int CMasternodeMan::CountEnabled(int nProtocolVersion) -{ - LOCK(cs); - - int nCount = 0; - nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion; - - if (deterministicMNManager->IsDIP3Active()) { - auto mnList = deterministicMNManager->GetListAtChainTip(); - nCount = (int)mnList.GetValidMNsCount(); - } else { - for (const auto& mnpair : mapMasternodes) { - if (mnpair.second.nProtocolVersion < nProtocolVersion || !mnpair.second.IsEnabled()) continue; - nCount++; - } - } - - return nCount; -} - -/* Only IPv4 masternodes are allowed in 12.1, saving this for later -int CMasternodeMan::CountByIP(int nNetworkType) -{ - LOCK(cs); - int nNodeCount = 0; - - for (const auto& mnpair : mapMasternodes) - if ((nNetworkType == NET_IPV4 && mnpair.second.addr.IsIPv4()) || - (nNetworkType == NET_TOR && mnpair.second.addr.IsTor()) || - (nNetworkType == NET_IPV6 && mnpair.second.addr.IsIPv6())) { - nNodeCount++; - } - - return nNodeCount; -} -*/ - -void CMasternodeMan::DsegUpdate(CNode* pnode, CConnman& connman) -{ - CNetMsgMaker msgMaker(pnode->GetSendVersion()); - LOCK(cs); - - if (deterministicMNManager->IsDIP3Active()) - return; - - CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0); - if(Params().NetworkIDString() == CBaseChainParams::MAIN) { - if(!(pnode->addr.IsRFC1918() || pnode->addr.IsLocal())) { - auto it = mWeAskedForMasternodeList.find(addrSquashed); - if(it != mWeAskedForMasternodeList.end() && GetTime() < (*it).second) { - LogPrintf("CMasternodeMan::DsegUpdate -- we already asked %s for the list; skipping...\n", addrSquashed.ToString()); - return; - } - } - } - - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSEG, COutPoint())); - - int64_t askAgain = GetTime() + DSEG_UPDATE_SECONDS; - mWeAskedForMasternodeList[addrSquashed] = askAgain; - - LogPrint("masternode", "CMasternodeMan::DsegUpdate -- asked %s for the list\n", pnode->addr.ToString()); } CMasternode* CMasternodeMan::Find(const COutPoint &outpoint) { LOCK(cs); - if (deterministicMNManager->IsDIP3Active()) { - // This code keeps compatibility to old code depending on the non-deterministic MN lists - // When deterministic MN lists get activated, we stop relying on the MNs we encountered due to MNBs and start - // using the MNs found in the deterministic MN manager. To keep compatibility, we create CMasternode entries - // for these and return them here. This is needed because we also need to track some data per MN that is not - // on-chain, like vote counts + // This code keeps compatibility to old code depending on the non-deterministic MN lists + // When deterministic MN lists get activated, we stop relying on the MNs we encountered due to MNBs and start + // using the MNs found in the deterministic MN manager. To keep compatibility, we create CMasternode entries + // for these and return them here. This is needed because we also need to track some data per MN that is not + // on-chain, like vote counts - auto mnList = deterministicMNManager->GetListAtChainTip(); - auto dmn = mnList.GetMNByCollateral(outpoint); - if (!dmn || !mnList.IsMNValid(dmn)) { - return nullptr; - } + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto dmn = mnList.GetMNByCollateral(outpoint); + if (!dmn || !mnList.IsMNValid(dmn)) { + return nullptr; + } - auto it = mapMasternodes.find(outpoint); - if (it != mapMasternodes.end()) { - return &(it->second); - } else { - // MN is not in mapMasternodes but in the deterministic list. Create an entry in mapMasternodes for compatibility with legacy code - CMasternode mn(outpoint.hash, dmn); - it = mapMasternodes.emplace(outpoint, mn).first; - return &(it->second); - } + auto it = mapMasternodes.find(outpoint); + if (it != mapMasternodes.end()) { + return &(it->second); } else { - auto it = mapMasternodes.find(outpoint); - return it == mapMasternodes.end() ? nullptr : &(it->second); - } -} - -bool CMasternodeMan::Get(const COutPoint& outpoint, CMasternode& masternodeRet) -{ - // Theses mutexes are recursive so double locking by the same thread is safe. - LOCK(cs); - CMasternode* mn = Find(outpoint); - if (!mn) - return false; - masternodeRet = *mn; - return true; -} - -bool CMasternodeMan::GetMasternodeInfo(const uint256& proTxHash, masternode_info_t& mnInfoRet) -{ - auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash); - if (!dmn) - return false; - return GetMasternodeInfo(dmn->collateralOutpoint, mnInfoRet); -} - -bool CMasternodeMan::GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet) -{ - LOCK(cs); - CMasternode* mn = Find(outpoint); - if (!mn) - return false; - mnInfoRet = mn->GetInfo(); - return true; -} - -bool CMasternodeMan::GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_info_t& mnInfoRet) { - LOCK(cs); - if (deterministicMNManager->IsDIP3Active()) { - return false; - } else { - for (const auto& mnpair : mapMasternodes) { - if (mnpair.second.legacyKeyIDOperator == keyIDOperator) { - mnInfoRet = mnpair.second.GetInfo(); - return true; - } - } - return false; - } -} - -bool CMasternodeMan::GetMasternodeInfo(const CScript& payee, masternode_info_t& mnInfoRet) -{ - if (deterministicMNManager->IsDIP3Active()) { - // we can't reliably search by payee as there might be duplicates. Also, keyIDCollateralAddress is not - // always the payout address as DIP3 allows using different keys for collateral and payouts - // this method is only used from ComputeBlockVersion, which has a different logic for deterministic MNs - // this method won't be reimplemented when removing the compatibility code - return false; - } else { - CTxDestination dest; - if (!ExtractDestination(payee, dest) || !boost::get(&dest)) - return false; - CKeyID keyId = *boost::get(&dest); - LOCK(cs); - for (const auto& mnpair : mapMasternodes) { - if (mnpair.second.keyIDCollateralAddress == keyId) { - mnInfoRet = mnpair.second.GetInfo(); - return true; - } - } - return false; - } -} - -bool CMasternodeMan::Has(const COutPoint& outpoint) -{ - LOCK(cs); - if (deterministicMNManager->IsDIP3Active()) { - return deterministicMNManager->GetListAtChainTip().HasValidMNByCollateral(outpoint); - } else { - return mapMasternodes.find(outpoint) != mapMasternodes.end(); - } -} - -// -// Deterministically select the oldest/best masternode to pay on the network -// -bool CMasternodeMan::GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet) -{ - return GetNextMasternodeInQueueForPayment(nCachedBlockHeight, fFilterSigTime, nCountRet, mnInfoRet); -} - -bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet) -{ - if (deterministicMNManager->IsDIP3Active(nBlockHeight)) { - return false; - } - - mnInfoRet = masternode_info_t(); - nCountRet = 0; - - if (!masternodeSync.IsWinnersListSynced()) { - // without winner list we can't reliably find the next winner anyway - return false; - } - - // Need LOCK2 here to ensure consistent locking order because the GetBlockHash call below locks cs_main - LOCK2(cs_main,cs); - - std::vector > vecMasternodeLastPaid; - - /* - Make a vector with all of the last paid times - */ - - int nMnCount = CountMasternodes(); - - for (const auto& mnpair : mapMasternodes) { - if(!mnpair.second.IsValidForPayment()) continue; - - //check protocol version - if(mnpair.second.nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; - - //it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it - //if(mnpayments.IsScheduled(mnpair.second, nBlockHeight)) continue; - - //it's too new, wait for a cycle - if(fFilterSigTime && mnpair.second.sigTime + (nMnCount*2.6*60) > GetAdjustedTime()) continue; - - //make sure it has at least as many confirmations as there are masternodes - if(GetUTXOConfirmations(mnpair.first) < nMnCount) continue; - - vecMasternodeLastPaid.push_back(std::make_pair(mnpair.second.GetLastPaidBlock(), &mnpair.second)); - } - - nCountRet = (int)vecMasternodeLastPaid.size(); - - //when the network is in the process of upgrading, don't penalize nodes that recently restarted - if(fFilterSigTime && nCountRet < nMnCount/3) - return GetNextMasternodeInQueueForPayment(nBlockHeight, false, nCountRet, mnInfoRet); - - // Sort them low to high - sort(vecMasternodeLastPaid.begin(), vecMasternodeLastPaid.end(), CompareLastPaidBlock()); - - uint256 blockHash; - if(!GetBlockHash(blockHash, nBlockHeight - 101)) { - LogPrintf("CMasternode::GetNextMasternodeInQueueForPayment -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", nBlockHeight - 101); - return false; - } - // Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one - // -- This doesn't look at who is being paid in the +8-10 blocks, allowing for double payments very rarely - // -- 1/100 payments should be a double payment on mainnet - (1/(3000/10))*2 - // -- (chance per block * chances before IsScheduled will fire) - int nTenthNetwork = nMnCount/10; - int nCountTenth = 0; - arith_uint256 nHighest = 0; - const CMasternode *pBestMasternode = nullptr; - for (const auto& s : vecMasternodeLastPaid) { - arith_uint256 nScore = s.second->CalculateScore(blockHash); - if(nScore > nHighest){ - nHighest = nScore; - pBestMasternode = s.second; - } - nCountTenth++; - if(nCountTenth >= nTenthNetwork) break; - } - if (pBestMasternode) { - mnInfoRet = pBestMasternode->GetInfo(); - } - return mnInfoRet.fInfoValid; -} - -std::map CMasternodeMan::GetFullMasternodeMap() -{ - LOCK(cs); - - if (deterministicMNManager->IsDIP3Active()) { - std::map result; - auto mnList = deterministicMNManager->GetListAtChainTip(); - for (const auto &p : mapMasternodes) { - auto dmn = mnList.GetMNByCollateral(p.first); - if (dmn && mnList.IsMNValid(dmn)) { - result.emplace(p.first, p.second); - } - } - return result; - } else { - return mapMasternodes; + // MN is not in mapMasternodes but in the deterministic list. Create an entry in mapMasternodes for compatibility with legacy code + CMasternode mn(outpoint.hash, dmn); + it = mapMasternodes.emplace(outpoint, mn).first; + return &(it->second); } } @@ -792,7 +152,7 @@ bool CMasternodeMan::GetMasternodeRank(const COutPoint& outpoint, int& nRankRet, { nRankRet = -1; - if (!masternodeSync.IsMasternodeListSynced()) + if (!masternodeSync.IsBlockchainSynced()) return false; // make sure we know about this block @@ -824,7 +184,7 @@ bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMast { vecMasternodeRanksRet.clear(); - if (!masternodeSync.IsMasternodeListSynced()) + if (!masternodeSync.IsBlockchainSynced()) return false; // make sure we know about this block @@ -874,944 +234,16 @@ void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman) }); } -std::pair > CMasternodeMan::PopScheduledMnbRequestConnection() -{ - LOCK(cs); - if (deterministicMNManager->IsDIP3Active()) { - return std::make_pair(CService(), std::set()); - } - if(listScheduledMnbRequestConnections.empty()) { - return std::make_pair(CService(), std::set()); - } - - std::set setResult; - - listScheduledMnbRequestConnections.sort(); - std::pair pairFront = listScheduledMnbRequestConnections.front(); - - // squash hashes from requests with the same CService as the first one into setResult - std::list< std::pair >::iterator it = listScheduledMnbRequestConnections.begin(); - while(it != listScheduledMnbRequestConnections.end()) { - if(pairFront.first == it->first) { - setResult.insert(it->second); - it = listScheduledMnbRequestConnections.erase(it); - } else { - // since list is sorted now, we can be sure that there is no more hashes left - // to ask for from this addr - break; - } - } - return std::make_pair(pairFront.first, setResult); -} - -void CMasternodeMan::ProcessPendingMnbRequests(CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) - return; - - std::pair > p = PopScheduledMnbRequestConnection(); - if (!(p.first == CService() || p.second.empty())) { - if (connman.IsMasternodeOrDisconnectRequested(p.first)) return; - mapPendingMNB.insert(std::make_pair(p.first, std::make_pair(GetTime(), p.second))); - connman.AddPendingMasternode(p.first); - } - - std::map > >::iterator itPendingMNB = mapPendingMNB.begin(); - while (itPendingMNB != mapPendingMNB.end()) { - bool fDone = connman.ForNode(itPendingMNB->first, [&](CNode* pnode) { - // compile request vector - std::vector vToFetch; - for (auto& nHash : itPendingMNB->second.second) { - if(nHash != uint256()) { - vToFetch.push_back(CInv(MSG_MASTERNODE_ANNOUNCE, nHash)); - LogPrint("masternode", "-- asking for mnb %s from addr=%s\n", nHash.ToString(), pnode->addr.ToString()); - } - } - - // ask for data - CNetMsgMaker msgMaker(pnode->GetSendVersion()); - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); - return true; - }); - - int64_t nTimeAdded = itPendingMNB->second.first; - if (fDone || (GetTime() - nTimeAdded > 15)) { - if (!fDone) { - LogPrint("masternode", "CMasternodeMan::%s -- failed to connect to %s\n", __func__, itPendingMNB->first.ToString()); - } - mapPendingMNB.erase(itPendingMNB++); - } else { - ++itPendingMNB; - } - } -} - -void CMasternodeMan::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) - return; - - if(fLiteMode) return; // disable all Dash specific functionality - - if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast - - CMasternodeBroadcast mnb; - vRecv >> mnb; - - { - LOCK(cs_main); - connman.RemoveAskFor(mnb.GetHash()); - } - - if(!masternodeSync.IsBlockchainSynced()) return; - - LogPrint("masternode", "MNANNOUNCE -- Masternode announce, masternode=%s\n", mnb.outpoint.ToStringShort()); - - int nDos = 0; - - if (CheckMnbAndUpdateMasternodeList(pfrom, mnb, nDos, connman)) { - // use announced Masternode as a peer - connman.AddNewAddress(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2*60*60); - } else if(nDos > 0) { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), nDos); - } - - if(fMasternodesAdded) { - NotifyMasternodeUpdates(connman); - } - } else if (strCommand == NetMsgType::MNPING) { //Masternode Ping - - CMasternodePing mnp; - vRecv >> mnp; - - uint256 nHash = mnp.GetHash(); - - { - LOCK(cs_main); - connman.RemoveAskFor(nHash); - } - - if(!masternodeSync.IsBlockchainSynced()) return; - - LogPrint("masternode", "MNPING -- Masternode ping, masternode=%s\n", mnp.masternodeOutpoint.ToStringShort()); - - // Need LOCK2 here to ensure consistent locking order because the CheckAndUpdate call below locks cs_main - LOCK2(cs_main, cs); - - if(mapSeenMasternodePing.count(nHash)) return; //seen - mapSeenMasternodePing.insert(std::make_pair(nHash, mnp)); - - LogPrint("masternode", "MNPING -- Masternode ping, masternode=%s new\n", mnp.masternodeOutpoint.ToStringShort()); - - // see if we have this Masternode - CMasternode* pmn = Find(mnp.masternodeOutpoint); - - if(pmn && mnp.fSentinelIsCurrent) - UpdateLastSentinelPingTime(); - - // too late, new MNANNOUNCE is required - if(pmn && pmn->IsNewStartRequired()) return; - - int nDos = 0; - if(mnp.CheckAndUpdate(pmn, false, nDos, connman)) return; - - if(nDos > 0) { - // if anything significant failed, mark that node - Misbehaving(pfrom->GetId(), nDos); - } else if(pmn != nullptr) { - // nothing significant failed, mn is a known one too - return; - } - - // something significant is broken or mn is unknown, - // we might have to ask for a masternode entry once - AskForMN(pfrom, mnp.masternodeOutpoint, connman); - - } else if (strCommand == NetMsgType::DSEG) { //Get Masternode list or specific entry - // Ignore such requests until we are fully synced. - // We could start processing this after masternode list is synced - // but this is a heavy one so it's better to finish sync first. - if (!masternodeSync.IsSynced()) return; - - COutPoint masternodeOutpoint; - vRecv >> masternodeOutpoint; - - LogPrint("masternode", "DSEG -- Masternode list, masternode=%s\n", masternodeOutpoint.ToStringShort()); - - if(masternodeOutpoint.IsNull()) { - SyncAll(pfrom, connman); - } else { - SyncSingle(pfrom, masternodeOutpoint, connman); - } - - } else if (strCommand == NetMsgType::MNVERIFY) { // Masternode Verify - - // Need LOCK2 here to ensure consistent locking order because all functions below call GetBlockHash which locks cs_main - LOCK2(cs_main, cs); - - CMasternodeVerification mnv; - vRecv >> mnv; - - { - LOCK(cs_main); - connman.RemoveAskFor(mnv.GetHash()); - } - - if(!masternodeSync.IsMasternodeListSynced()) return; - - if(mnv.vchSig1.empty()) { - // CASE 1: someone asked me to verify myself /IP we are using/ - SendVerifyReply(pfrom, mnv, connman); - } else if (mnv.vchSig2.empty()) { - // CASE 2: we _probably_ got verification we requested from some masternode - ProcessVerifyReply(pfrom, mnv); - } else { - // CASE 3: we _probably_ got verification broadcast signed by some masternode which verified another one - ProcessVerifyBroadcast(pfrom, mnv); - } - } -} - -void CMasternodeMan::SyncSingle(CNode* pnode, const COutPoint& outpoint, CConnman& connman) -{ - // do not provide any data until our node is synced - if (!masternodeSync.IsSynced()) return; - - LOCK(cs); - - auto it = mapMasternodes.find(outpoint); - - if(it != mapMasternodes.end()) { - if (it->second.addr.IsRFC1918() || it->second.addr.IsLocal()) return; // do not send local network masternode - // NOTE: send masternode regardless of its current state, the other node will need it to verify old votes. - LogPrint("masternode", "CMasternodeMan::%s -- Sending Masternode entry: masternode=%s addr=%s\n", __func__, outpoint.ToStringShort(), it->second.addr.ToString()); - PushDsegInvs(pnode, it->second); - LogPrintf("CMasternodeMan::%s -- Sent 1 Masternode inv to peer=%d\n", __func__, pnode->id); - } -} - -void CMasternodeMan::SyncAll(CNode* pnode, CConnman& connman) -{ - // do not provide any data until our node is synced - if (!masternodeSync.IsSynced()) return; - - // local network - bool isLocal = (pnode->addr.IsRFC1918() || pnode->addr.IsLocal()); - - CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0); - // should only ask for this once - if(!isLocal && Params().NetworkIDString() == CBaseChainParams::MAIN) { - LOCK2(cs_main, cs); - auto it = mAskedUsForMasternodeList.find(addrSquashed); - if (it != mAskedUsForMasternodeList.end() && it->second > GetTime()) { - Misbehaving(pnode->GetId(), 34); - LogPrintf("CMasternodeMan::%s -- peer already asked me for the list, peer=%d\n", __func__, pnode->id); - return; - } - int64_t askAgain = GetTime() + DSEG_UPDATE_SECONDS; - mAskedUsForMasternodeList[addrSquashed] = askAgain; - } - - int nInvCount = 0; - - LOCK(cs); - - for (const auto& mnpair : mapMasternodes) { - if (Params().RequireRoutableExternalIP() && - (mnpair.second.addr.IsRFC1918() || mnpair.second.addr.IsLocal())) - continue; // do not send local network masternode - // NOTE: send masternode regardless of its current state, the other node will need it to verify old votes. - LogPrint("masternode", "CMasternodeMan::%s -- Sending Masternode entry: masternode=%s addr=%s\n", __func__, mnpair.first.ToStringShort(), mnpair.second.addr.ToString()); - PushDsegInvs(pnode, mnpair.second); - nInvCount++; - } - - connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount)); - LogPrintf("CMasternodeMan::%s -- Sent %d Masternode invs to peer=%d\n", __func__, nInvCount, pnode->id); -} - -void CMasternodeMan::PushDsegInvs(CNode* pnode, const CMasternode& mn) -{ - AssertLockHeld(cs); - - CMasternodeBroadcast mnb(mn); - CMasternodePing mnp = mnb.lastPing; - uint256 hashMNB = mnb.GetHash(); - uint256 hashMNP = mnp.GetHash(); - pnode->PushInventory(CInv(MSG_MASTERNODE_ANNOUNCE, hashMNB)); - pnode->PushInventory(CInv(MSG_MASTERNODE_PING, hashMNP)); - mapSeenMasternodeBroadcast.insert(std::make_pair(hashMNB, std::make_pair(GetTime(), mnb))); - mapSeenMasternodePing.insert(std::make_pair(hashMNP, mnp)); -} - -// Verification of masternodes via unique direct requests. - -void CMasternodeMan::DoFullVerificationStep(CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) - return; - - if(activeMasternodeInfo.outpoint.IsNull()) return; - if(!masternodeSync.IsSynced()) return; - - rank_pair_vec_t vecMasternodeRanks; - GetMasternodeRanks(vecMasternodeRanks, nCachedBlockHeight - 1, MIN_POSE_PROTO_VERSION); - - std::vector vAddr; - - { - LOCK(cs); - - int nMyRank = -1; - int nRanksTotal = (int)vecMasternodeRanks.size(); - - // send verify requests only if we are in top MAX_POSE_RANK - for (auto& rankPair : vecMasternodeRanks) { - if(rankPair.first > MAX_POSE_RANK) { - LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Must be in top %d to send verify request\n", - (int)MAX_POSE_RANK); - return; - } - if(rankPair.second->collateralOutpoint == activeMasternodeInfo.outpoint) { - nMyRank = rankPair.first; - LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d masternodes\n", - nMyRank, nRanksTotal, (int)MAX_POSE_CONNECTIONS); - break; - } - } - - // edge case: list is too short and this masternode is not enabled - if(nMyRank == -1) return; - - // send verify requests to up to MAX_POSE_CONNECTIONS masternodes - // starting from MAX_POSE_RANK + nMyRank and using MAX_POSE_CONNECTIONS as a step - int nOffset = MAX_POSE_RANK + nMyRank - 1; - if(nOffset >= (int)vecMasternodeRanks.size()) return; - - auto it = vecMasternodeRanks.begin() + nOffset; - while(it != vecMasternodeRanks.end()) { -// if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) { -// LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping...\n", -// it->second.IsPoSeVerified() ? "verified" : "", -// it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "", -// it->second.IsPoSeBanned() ? "banned" : "", -// it->second.outpoint.ToStringShort(), it->second.addr.ToString()); -// nOffset += MAX_POSE_CONNECTIONS; -// if(nOffset >= (int)vecMasternodeRanks.size()) break; -// it += MAX_POSE_CONNECTIONS; -// continue; -// } - LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Verifying masternode %s rank %d/%d address %s\n", - it->second->collateralOutpoint.ToStringShort(), it->first, nRanksTotal, it->second->pdmnState->addr.ToString()); - CAddress addr = CAddress(it->second->pdmnState->addr, NODE_NETWORK); - if(CheckVerifyRequestAddr(addr, connman)) { - vAddr.push_back(addr); - if((int)vAddr.size() >= MAX_POSE_CONNECTIONS) break; - } - nOffset += MAX_POSE_CONNECTIONS; - if(nOffset >= (int)vecMasternodeRanks.size()) break; - it += MAX_POSE_CONNECTIONS; - } - } // cs - - for (const auto& addr : vAddr) { - PrepareVerifyRequest(addr, connman); - } - - LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Prepared verification requests for %d masternodes\n", vAddr.size()); -} - -// This function tries to find masternodes with the same addr, -// find a verified one and ban all the other. If there are many nodes -// with the same addr but none of them is verified yet, then none of them are banned. -// It could take many times to run this before most of the duplicate nodes are banned. - -void CMasternodeMan::CheckSameAddr() -{ - if (deterministicMNManager->IsDIP3Active()) - return; - - if(!masternodeSync.IsSynced() || mapMasternodes.empty()) return; - - std::vector vBan; - std::vector vSortedByAddr; - - { - LOCK(cs); - - CMasternode* pprevMasternode = nullptr; - CMasternode* pverifiedMasternode = nullptr; - - for (auto& mnpair : mapMasternodes) { - vSortedByAddr.push_back(&mnpair.second); - } - - sort(vSortedByAddr.begin(), vSortedByAddr.end(), CompareByAddr()); - - for (const auto& pmn : vSortedByAddr) { - // check only (pre)enabled masternodes - if(!pmn->IsEnabled() && !pmn->IsPreEnabled()) continue; - // initial step - if(!pprevMasternode) { - pprevMasternode = pmn; - pverifiedMasternode = pmn->IsPoSeVerified() ? pmn : nullptr; - continue; - } - // second+ step - if(pmn->addr == pprevMasternode->addr) { - if(pverifiedMasternode) { - // another masternode with the same ip is verified, ban this one - vBan.push_back(pmn); - } else if(pmn->IsPoSeVerified()) { - // this masternode with the same ip is verified, ban previous one - vBan.push_back(pprevMasternode); - // and keep a reference to be able to ban following masternodes with the same ip - pverifiedMasternode = pmn; - } - } else { - pverifiedMasternode = pmn->IsPoSeVerified() ? pmn : nullptr; - } - pprevMasternode = pmn; - } - } - - // ban duplicates - for (auto& pmn : vBan) { - LogPrintf("CMasternodeMan::CheckSameAddr -- increasing PoSe ban score for masternode %s\n", pmn->outpoint.ToStringShort()); - pmn->IncreasePoSeBanScore(); - } -} - -bool CMasternodeMan::CheckVerifyRequestAddr(const CAddress& addr, CConnman& connman) -{ - if (deterministicMNManager->IsDIP3Active()) - return false; - - if(netfulfilledman.HasFulfilledRequest(addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request")) { - // we already asked for verification, not a good idea to do this too often, skip it - LogPrint("masternode", "CMasternodeMan::%s -- too many requests, skipping... addr=%s\n", __func__, addr.ToString()); - return false; - } - - return !connman.IsMasternodeOrDisconnectRequested(addr); -} - -void CMasternodeMan::PrepareVerifyRequest(const CAddress& addr, CConnman& connman) -{ - connman.AddPendingMasternode(addr); - // use random nonce, store it and require node to reply with correct one later - CMasternodeVerification mnv(addr, GetRandInt(999999), nCachedBlockHeight - 1); - LOCK(cs_mapPendingMNV); - mapPendingMNV.insert(std::make_pair(addr, std::make_pair(GetTime(), mnv))); - LogPrintf("CMasternodeMan::%s -- verifying node using nonce %d addr=%s\n", __func__, mnv.nonce, addr.ToString()); -} - -void CMasternodeMan::ProcessPendingMnvRequests(CConnman& connman) -{ - LOCK(cs_mapPendingMNV); - - if (deterministicMNManager->IsDIP3Active()) - return; - - std::map >::iterator itPendingMNV = mapPendingMNV.begin(); - - while (itPendingMNV != mapPendingMNV.end()) { - bool fDone = connman.ForNode(itPendingMNV->first, [&](CNode* pnode) { - netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request"); - // use random nonce, store it and require node to reply with correct one later - mWeAskedForVerification[pnode->addr] = itPendingMNV->second.second; - LogPrint("masternode", "-- verifying node using nonce %d addr=%s\n", itPendingMNV->second.second.nonce, pnode->addr.ToString()); - CNetMsgMaker msgMaker(pnode->GetSendVersion()); // TODO this gives a warning about version not being set (we should wait for VERSION exchange) - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MNVERIFY, itPendingMNV->second.second)); - return true; - }); - - int64_t nTimeAdded = itPendingMNV->second.first; - if (fDone || (GetTime() - nTimeAdded > 15)) { - if (!fDone) { - LogPrint("masternode", "CMasternodeMan::%s -- failed to connect to %s\n", __func__, itPendingMNV->first.ToString()); - } - mapPendingMNV.erase(itPendingMNV++); - } else { - ++itPendingMNV; - } - } -} - -void CMasternodeMan::SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv, CConnman& connman) -{ - AssertLockHeld(cs_main); - - if (deterministicMNManager->IsDIP3Active()) - return; - - // only masternodes can sign this, why would someone ask regular node? - if(!fMasternodeMode) { - // do not ban, malicious node might be using my IP - // and trying to confuse the node which tries to verify it - return; - } - - if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-reply")) { - // peer should not ask us that often - LogPrintf("MasternodeMan::SendVerifyReply -- ERROR: peer already asked me recently, peer=%d\n", pnode->id); - Misbehaving(pnode->id, 20); - return; - } - - uint256 blockHash; - if(!GetBlockHash(blockHash, mnv.nBlockHeight)) { - LogPrintf("MasternodeMan::SendVerifyReply -- can't get block hash for unknown block height %d, peer=%d\n", mnv.nBlockHeight, pnode->id); - return; - } - - std::string strError; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = mnv.GetSignatureHash1(blockHash); - - if(!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, mnv.vchSig1)) { - LogPrintf("CMasternodeMan::SendVerifyReply -- SignHash() failed\n"); - return; - } - - if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig1, strError)) { - LogPrintf("CMasternodeMan::SendVerifyReply -- VerifyHash() failed, error: %s\n", strError); - return; - } - } else { - std::string strMessage = strprintf("%s%d%s", activeMasternodeInfo.service.ToString(false), mnv.nonce, blockHash.ToString()); - - if(!CMessageSigner::SignMessage(strMessage, mnv.vchSig1, activeMasternodeInfo.legacyKeyOperator)) { - LogPrintf("MasternodeMan::SendVerifyReply -- SignMessage() failed\n"); - return; - } - - if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig1, strMessage, strError)) { - LogPrintf("MasternodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s\n", strError); - return; - } - } - - CNetMsgMaker msgMaker(pnode->GetSendVersion()); - connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MNVERIFY, mnv)); - netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-reply"); -} - -void CMasternodeMan::ProcessVerifyReply(CNode* pnode, CMasternodeVerification& mnv) -{ - AssertLockHeld(cs_main); - - if (deterministicMNManager->IsDIP3Active()) - return; - - std::string strError; - - // did we even ask for it? if that's the case we should have matching fulfilled request - if(!netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request")) { - LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: we didn't ask for verification of %s, peer=%d\n", pnode->addr.ToString(), pnode->id); - Misbehaving(pnode->id, 20); - return; - } - - // Received nonce for a known address must match the one we sent - if(mWeAskedForVerification[pnode->addr].nonce != mnv.nonce) { - LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: wrong nounce: requested=%d, received=%d, peer=%d\n", - mWeAskedForVerification[pnode->addr].nonce, mnv.nonce, pnode->id); - Misbehaving(pnode->id, 20); - return; - } - - // Received nBlockHeight for a known address must match the one we sent - if(mWeAskedForVerification[pnode->addr].nBlockHeight != mnv.nBlockHeight) { - LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: wrong nBlockHeight: requested=%d, received=%d, peer=%d\n", - mWeAskedForVerification[pnode->addr].nBlockHeight, mnv.nBlockHeight, pnode->id); - Misbehaving(pnode->id, 20); - return; - } - - uint256 blockHash; - if(!GetBlockHash(blockHash, mnv.nBlockHeight)) { - // this shouldn't happen... - LogPrintf("MasternodeMan::ProcessVerifyReply -- can't get block hash for unknown block height %d, peer=%d\n", mnv.nBlockHeight, pnode->id); - return; - } - - // we already verified this address, why node is spamming? - if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-done")) { - LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: already verified %s recently\n", pnode->addr.ToString()); - Misbehaving(pnode->id, 20); - return; - } - - { - LOCK(cs); - - CMasternode* prealMasternode = nullptr; - std::vector vpMasternodesToBan; - - uint256 hash1 = mnv.GetSignatureHash1(blockHash); - std::string strMessage1 = strprintf("%s%d%s", pnode->addr.ToString(false), mnv.nonce, blockHash.ToString()); - - for (auto& mnpair : mapMasternodes) { - if(CAddress(mnpair.second.addr, NODE_NETWORK) == pnode->addr) { - bool fFound = false; - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - fFound = CHashSigner::VerifyHash(hash1, mnpair.second.legacyKeyIDOperator, mnv.vchSig1, strError); - // we don't care about mnv with signature in old format - } else { - fFound = CMessageSigner::VerifyMessage(mnpair.second.legacyKeyIDOperator, mnv.vchSig1, strMessage1, strError); - } - if (fFound) { - // found it! - prealMasternode = &mnpair.second; - if(!mnpair.second.IsPoSeVerified()) { - mnpair.second.DecreasePoSeBanScore(); - } - netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-done"); - - // we can only broadcast it if we are an activated masternode - if(activeMasternodeInfo.outpoint.IsNull()) continue; - // update ... - mnv.addr = mnpair.second.addr; - mnv.masternodeOutpoint1 = mnpair.second.outpoint; - mnv.masternodeOutpoint2 = activeMasternodeInfo.outpoint; - // ... and sign it - std::string strError; - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash2 = mnv.GetSignatureHash2(blockHash); - - if(!CHashSigner::SignHash(hash2, activeMasternodeInfo.legacyKeyOperator, mnv.vchSig2)) { - LogPrintf("MasternodeMan::ProcessVerifyReply -- SignHash() failed\n"); - return; - } - - if(!CHashSigner::VerifyHash(hash2, activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig2, strError)) { - LogPrintf("MasternodeMan::ProcessVerifyReply -- VerifyHash() failed, error: %s\n", strError); - return; - } - } else { - std::string strMessage2 = strprintf("%s%d%s%s%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString(), - mnv.masternodeOutpoint1.ToStringShort(), mnv.masternodeOutpoint2.ToStringShort()); - - if(!CMessageSigner::SignMessage(strMessage2, mnv.vchSig2, activeMasternodeInfo.legacyKeyOperator)) { - LogPrintf("MasternodeMan::ProcessVerifyReply -- SignMessage() failed\n"); - return; - } - - if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig2, strMessage2, strError)) { - LogPrintf("MasternodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s\n", strError); - return; - } - } - - mWeAskedForVerification[pnode->addr] = mnv; - mapSeenMasternodeVerification.insert(std::make_pair(mnv.GetHash(), mnv)); - mnv.Relay(); - - } else { - vpMasternodesToBan.push_back(&mnpair.second); - } - } - } - // no real masternode found?... - if(!prealMasternode) { - // this should never be the case normally, - // only if someone is trying to game the system in some way or smth like that - LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: no real masternode found for addr %s\n", pnode->addr.ToString()); - Misbehaving(pnode->id, 20); - return; - } - LogPrintf("CMasternodeMan::ProcessVerifyReply -- verified real masternode %s for addr %s\n", - prealMasternode->outpoint.ToStringShort(), pnode->addr.ToString()); - // increase ban score for everyone else - for (const auto& pmn : vpMasternodesToBan) { - pmn->IncreasePoSeBanScore(); - LogPrint("masternode", "CMasternodeMan::ProcessVerifyReply -- increased PoSe ban score for %s addr %s, new score %d\n", - prealMasternode->outpoint.ToStringShort(), pnode->addr.ToString(), pmn->nPoSeBanScore); - } - if(!vpMasternodesToBan.empty()) - LogPrintf("CMasternodeMan::ProcessVerifyReply -- PoSe score increased for %d fake masternodes, addr %s\n", - (int)vpMasternodesToBan.size(), pnode->addr.ToString()); - } -} - -void CMasternodeMan::ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerification& mnv) -{ - AssertLockHeld(cs_main); - - if (deterministicMNManager->IsDIP3Active()) - return; - - std::string strError; - - if(mapSeenMasternodeVerification.find(mnv.GetHash()) != mapSeenMasternodeVerification.end()) { - // we already have one - return; - } - mapSeenMasternodeVerification[mnv.GetHash()] = mnv; - - // we don't care about history - if(mnv.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS) { - LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- Outdated: current block %d, verification block %d, peer=%d\n", - nCachedBlockHeight, mnv.nBlockHeight, pnode->id); - return; - } - - if(mnv.masternodeOutpoint1 == mnv.masternodeOutpoint2) { - LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- ERROR: same outpoints %s, peer=%d\n", - mnv.masternodeOutpoint1.ToStringShort(), pnode->id); - // that was NOT a good idea to cheat and verify itself, - // ban the node we received such message from - Misbehaving(pnode->id, 100); - return; - } - - uint256 blockHash; - if(!GetBlockHash(blockHash, mnv.nBlockHeight)) { - // this shouldn't happen... - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- Can't get block hash for unknown block height %d, peer=%d\n", mnv.nBlockHeight, pnode->id); - return; - } - - int nRank; - - if (!GetMasternodeRank(mnv.masternodeOutpoint2, nRank, mnv.nBlockHeight, MIN_POSE_PROTO_VERSION)) { - LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- Can't calculate rank for masternode %s\n", - mnv.masternodeOutpoint2.ToStringShort()); - return; - } - - if(nRank > MAX_POSE_RANK) { - LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- Masternode %s is not in top %d, current rank %d, peer=%d\n", - mnv.masternodeOutpoint2.ToStringShort(), (int)MAX_POSE_RANK, nRank, pnode->id); - return; - } - - { - LOCK(cs); - - CMasternode* pmn1 = Find(mnv.masternodeOutpoint1); - if(!pmn1) { - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode1 %s\n", mnv.masternodeOutpoint1.ToStringShort()); - return; - } - - CMasternode* pmn2 = Find(mnv.masternodeOutpoint2); - if(!pmn2) { - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode2 %s\n", mnv.masternodeOutpoint2.ToStringShort()); - return; - } - - if(pmn1->addr != mnv.addr) { - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- addr %s does not match %s\n", mnv.addr.ToString(), pmn1->addr.ToString()); - return; - } - - if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash1 = mnv.GetSignatureHash1(blockHash); - uint256 hash2 = mnv.GetSignatureHash2(blockHash); - - if(!CHashSigner::VerifyHash(hash1, pmn1->legacyKeyIDOperator, mnv.vchSig1, strError)) { - LogPrintf("MasternodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s\n", strError); - return; - } - - if(!CHashSigner::VerifyHash(hash2, pmn2->legacyKeyIDOperator, mnv.vchSig2, strError)) { - LogPrintf("MasternodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s\n", strError); - return; - } - } else { - std::string strMessage1 = strprintf("%s%d%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString()); - std::string strMessage2 = strprintf("%s%d%s%s%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString(), - mnv.masternodeOutpoint1.ToStringShort(), mnv.masternodeOutpoint2.ToStringShort()); - - if(!CMessageSigner::VerifyMessage(pmn1->legacyKeyIDOperator, mnv.vchSig1, strMessage1, strError)) { - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode1 failed, error: %s\n", strError); - return; - } - - if(!CMessageSigner::VerifyMessage(pmn2->legacyKeyIDOperator, mnv.vchSig2, strMessage2, strError)) { - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode2 failed, error: %s\n", strError); - return; - } - } - - if(!pmn1->IsPoSeVerified()) { - pmn1->DecreasePoSeBanScore(); - } - mnv.Relay(); - - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- verified masternode %s for addr %s\n", - pmn1->outpoint.ToStringShort(), pmn1->addr.ToString()); - - // increase ban score for everyone else with the same addr - int nCount = 0; - for (auto& mnpair : mapMasternodes) { - if(mnpair.second.addr != mnv.addr || mnpair.first == mnv.masternodeOutpoint1) continue; - mnpair.second.IncreasePoSeBanScore(); - nCount++; - LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- increased PoSe ban score for %s addr %s, new score %d\n", - mnpair.first.ToStringShort(), mnpair.second.addr.ToString(), mnpair.second.nPoSeBanScore); - } - if(nCount) - LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- PoSe score increased for %d fake masternodes, addr %s\n", - nCount, pmn1->addr.ToString()); - } -} - std::string CMasternodeMan::ToString() const { std::ostringstream info; - if (deterministicMNManager->IsDIP3Active()) { - info << "Masternodes: masternode object count: " << (int)mapMasternodes.size() << - ", deterministic masternode count: " << deterministicMNManager->GetListAtChainTip().GetAllMNsCount() << - ", nDsqCount: " << (int)nDsqCount; - } else { - info << "Masternodes: " << (int)mapMasternodes.size() << - ", peers who asked us for Masternode list: " << (int)mAskedUsForMasternodeList.size() << - ", peers we asked for Masternode list: " << (int)mWeAskedForMasternodeList.size() << - ", entries in Masternode list we asked for: " << (int)mWeAskedForMasternodeListEntry.size() << - ", nDsqCount: " << (int)nDsqCount; - } + info << "Masternodes: masternode object count: " << (int)mapMasternodes.size() << + ", deterministic masternode count: " << deterministicMNManager->GetListAtChainTip().GetAllMNsCount() << + ", nDsqCount: " << (int)nDsqCount; return info.str(); } -bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBroadcast mnb, int& nDos, CConnman& connman) -{ - // Need to lock cs_main here to ensure consistent locking order because the SimpleCheck call below locks cs_main - LOCK(cs_main); - - if (deterministicMNManager->IsDIP3Active()) - return false; - - { - LOCK(cs); - nDos = 0; - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s\n", mnb.outpoint.ToStringShort()); - - uint256 hash = mnb.GetHash(); - if(mapSeenMasternodeBroadcast.count(hash) && !mnb.fRecovery) { //seen - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen\n", mnb.outpoint.ToStringShort()); - // less then 2 pings left before this MN goes into non-recoverable state, bump sync timeout - if(GetTime() - mapSeenMasternodeBroadcast[hash].first > MASTERNODE_NEW_START_REQUIRED_SECONDS - MASTERNODE_MIN_MNP_SECONDS * 2) { - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen update\n", mnb.outpoint.ToStringShort()); - mapSeenMasternodeBroadcast[hash].first = GetTime(); - masternodeSync.BumpAssetLastTime("CMasternodeMan::CheckMnbAndUpdateMasternodeList - seen"); - } - // did we ask this node for it? - if(pfrom && IsMnbRecoveryRequested(hash) && GetTime() < mMnbRecoveryRequests[hash].first) { - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request\n", hash.ToString()); - if(mMnbRecoveryRequests[hash].second.count(pfrom->addr)) { - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request, addr=%s\n", hash.ToString(), pfrom->addr.ToString()); - // do not allow node to send same mnb multiple times in recovery mode - mMnbRecoveryRequests[hash].second.erase(pfrom->addr); - // does it have newer lastPing? - if(mnb.lastPing.sigTime > mapSeenMasternodeBroadcast[hash].second.lastPing.sigTime) { - // simulate Check - CMasternode mnTemp = CMasternode(mnb); - mnTemp.Check(); - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request, addr=%s, better lastPing: %d min ago, projected mn state: %s\n", hash.ToString(), pfrom->addr.ToString(), (GetAdjustedTime() - mnb.lastPing.sigTime)/60, mnTemp.GetStateString()); - if(mnTemp.IsValidStateForAutoStart(mnTemp.nActiveState)) { - // this node thinks it's a good one - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen good\n", mnb.outpoint.ToStringShort()); - mMnbRecoveryGoodReplies[hash].push_back(mnb); - } - } - } - } - return true; - } - mapSeenMasternodeBroadcast.insert(std::make_pair(hash, std::make_pair(GetTime(), mnb))); - - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s new\n", mnb.outpoint.ToStringShort()); - - if(!mnb.SimpleCheck(nDos)) { - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- SimpleCheck() failed, masternode=%s\n", mnb.outpoint.ToStringShort()); - return false; - } - - // search Masternode list - CMasternode* pmn = Find(mnb.outpoint); - if(pmn) { - CMasternodeBroadcast mnbOld = mapSeenMasternodeBroadcast[CMasternodeBroadcast(*pmn).GetHash()].second; - if(!mnb.Update(pmn, nDos, connman)) { - LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Update() failed, masternode=%s\n", mnb.outpoint.ToStringShort()); - return false; - } - if(hash != mnbOld.GetHash()) { - mapSeenMasternodeBroadcast.erase(mnbOld.GetHash()); - } - return true; - } - } - - if(mnb.CheckOutpoint(nDos)) { - Add(mnb); - masternodeSync.BumpAssetLastTime("CMasternodeMan::CheckMnbAndUpdateMasternodeList - new"); - // if it matches our Masternode privkey... - if(fMasternodeMode && mnb.legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator) { - mnb.nPoSeBanScore = -MASTERNODE_POSE_BAN_MAX_SCORE; - if(mnb.nProtocolVersion == PROTOCOL_VERSION) { - // ... and PROTOCOL_VERSION, then we've been remotely activated ... - LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Got NEW Masternode entry: masternode=%s sigTime=%lld addr=%s\n", - mnb.outpoint.ToStringShort(), mnb.sigTime, mnb.addr.ToString()); - legacyActiveMasternodeManager.ManageState(connman); - } else { - // ... otherwise we need to reactivate our node, do not add it to the list and do not relay - // but also do not ban the node we get this message from - LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList -- wrong PROTOCOL_VERSION, re-activate your MN: message nProtocolVersion=%d PROTOCOL_VERSION=%d\n", mnb.nProtocolVersion, PROTOCOL_VERSION); - return false; - } - } - mnb.Relay(connman); - } else { - LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Rejected Masternode entry: %s addr=%s\n", mnb.outpoint.ToStringShort(), mnb.addr.ToString()); - return false; - } - - return true; -} - -void CMasternodeMan::UpdateLastPaid(const CBlockIndex* pindex) -{ - LOCK2(cs_main, cs); - - if(fLiteMode || !masternodeSync.IsWinnersListSynced() || mapMasternodes.empty()) return; - - static int nLastRunBlockHeight = 0; - // Scan at least LAST_PAID_SCAN_BLOCKS but no more than mnpayments.GetStorageLimit() - int nMaxBlocksToScanBack = std::max(LAST_PAID_SCAN_BLOCKS, nCachedBlockHeight - nLastRunBlockHeight); - nMaxBlocksToScanBack = std::min(nMaxBlocksToScanBack, mnpayments.GetStorageLimit()); - - LogPrint("masternode", "CMasternodeMan::UpdateLastPaid -- nCachedBlockHeight=%d, nLastRunBlockHeight=%d, nMaxBlocksToScanBack=%d\n", - nCachedBlockHeight, nLastRunBlockHeight, nMaxBlocksToScanBack); - - for (auto& mnpair : mapMasternodes) { - mnpair.second.UpdateLastPaid(pindex, nMaxBlocksToScanBack); - } - - nLastRunBlockHeight = nCachedBlockHeight; -} - -void CMasternodeMan::UpdateLastSentinelPingTime() -{ - LOCK(cs); - if (deterministicMNManager->IsDIP3Active()) - return; - nLastSentinelPingTime = GetTime(); -} - -bool CMasternodeMan::IsSentinelPingActive() -{ - LOCK(cs); - // Check if any masternodes have voted recently, otherwise return false - return (GetTime() - nLastSentinelPingTime) <= MASTERNODE_SENTINEL_PING_MAX_SECONDS; -} - bool CMasternodeMan::AddGovernanceVote(const COutPoint& outpoint, uint256 nGovernanceObjectHash) { LOCK(cs); @@ -1831,129 +263,6 @@ void CMasternodeMan::RemoveGovernanceObject(uint256 nGovernanceObjectHash) } } -void CMasternodeMan::CheckMasternode(const CKeyID& keyIDOperator, bool fForce) -{ - LOCK2(cs_main, cs); - if (deterministicMNManager->IsDIP3Active()) - return; - for (auto& mnpair : mapMasternodes) { - if (mnpair.second.legacyKeyIDOperator == keyIDOperator) { - mnpair.second.Check(fForce); - return; - } - } -} - -bool CMasternodeMan::IsMasternodePingedWithin(const COutPoint& outpoint, int nSeconds, int64_t nTimeToCheckAt) -{ - LOCK(cs); - CMasternode* pmn = Find(outpoint); - return pmn ? pmn->IsPingedWithin(nSeconds, nTimeToCheckAt) : false; -} - -void CMasternodeMan::SetMasternodeLastPing(const COutPoint& outpoint, const CMasternodePing& mnp) -{ - LOCK(cs); - if (deterministicMNManager->IsDIP3Active()) - return; - CMasternode* pmn = Find(outpoint); - if(!pmn) { - return; - } - pmn->lastPing = mnp; - if(mnp.fSentinelIsCurrent) { - UpdateLastSentinelPingTime(); - } - mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp)); - - CMasternodeBroadcast mnb(*pmn); - uint256 hash = mnb.GetHash(); - if(mapSeenMasternodeBroadcast.count(hash)) { - mapSeenMasternodeBroadcast[hash].second.lastPing = mnp; - } -} - -void CMasternodeMan::UpdatedBlockTip(const CBlockIndex *pindex) -{ - nCachedBlockHeight = pindex->nHeight; - LogPrint("masternode", "CMasternodeMan::UpdatedBlockTip -- nCachedBlockHeight=%d\n", nCachedBlockHeight); - - AddDeterministicMasternodes(); - RemoveNonDeterministicMasternodes(); - - CheckSameAddr(); - - if(fMasternodeMode) { - // normal wallet does not need to update this every block, doing update on rpc call should be enough - UpdateLastPaid(pindex); - } -} - -void CMasternodeMan::WarnMasternodeDaemonUpdates() -{ - LOCK(cs); - - static bool fWarned = false; - - if (fWarned || !size() || !masternodeSync.IsMasternodeListSynced()) - return; - - int nUpdatedMasternodes{0}; - - for (const auto& mnpair : mapMasternodes) { - if (mnpair.second.lastPing.nDaemonVersion > CLIENT_VERSION) { - ++nUpdatedMasternodes; - } - } - - // Warn only when at least half of known masternodes already updated - if (nUpdatedMasternodes < size() / 2) - return; - - std::string strWarning; - if (nUpdatedMasternodes != size()) { - strWarning = strprintf(_("Warning: At least %d of %d masternodes are running on a newer software version. Please check latest releases, you might need to update too."), - nUpdatedMasternodes, size()); - } else { - // someone was postponing this update for way too long probably - strWarning = strprintf(_("Warning: Every masternode (out of %d known ones) is running on a newer software version. Please check latest releases, it's very likely that you missed a major/critical update."), - size()); - } - - // notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user - SetMiscWarning(strWarning); - // trigger GUI update - uiInterface.NotifyAlertChanged(SerializeHash(strWarning), CT_NEW); - // trigger cmd-line notification - CAlert::Notify(strWarning); - - fWarned = true; -} - -void CMasternodeMan::NotifyMasternodeUpdates(CConnman& connman, bool forceAddedChecks, bool forceRemovedChecks) -{ - // Avoid double locking - bool fMasternodesAddedLocal = false; - bool fMasternodesRemovedLocal = false; - { - LOCK(cs); - fMasternodesAddedLocal = fMasternodesAdded; - fMasternodesRemovedLocal = fMasternodesRemoved; - } - - if(fMasternodesAddedLocal || forceAddedChecks) { - governance.CheckMasternodeOrphanObjects(connman); - governance.CheckMasternodeOrphanVotes(connman); - } - if(fMasternodesRemovedLocal || forceRemovedChecks) { - governance.UpdateCachesAndClean(); - } - - LOCK(cs); - fMasternodesAdded = false; - fMasternodesRemoved = false; -} - void CMasternodeMan::DoMaintenance(CConnman& connman) { if(fLiteMode) return; // disable all Dash specific functionality @@ -1965,19 +274,7 @@ void CMasternodeMan::DoMaintenance(CConnman& connman) nTick++; - // make sure to check all masternodes first - mnodeman.Check(); - - mnodeman.ProcessPendingMnbRequests(connman); - mnodeman.ProcessPendingMnvRequests(connman); - if(nTick % 60 == 0) { mnodeman.ProcessMasternodeConnections(connman); - mnodeman.CheckAndRemove(connman); - mnodeman.WarnMasternodeDaemonUpdates(); - } - - if(fMasternodeMode && (nTick % (60 * 5) == 0)) { - mnodeman.DoFullVerificationStep(connman); } } diff --git a/src/masternodeman.h b/src/masternodeman.h index aa30b2e4fc..d812405da6 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -26,76 +26,20 @@ public: private: static const std::string SERIALIZATION_VERSION_STRING; - static const int DSEG_UPDATE_SECONDS = 3 * 60 * 60; - - static const int LAST_PAID_SCAN_BLOCKS; - - static const int MIN_POSE_PROTO_VERSION = 70203; - static const int MAX_POSE_CONNECTIONS = 10; - static const int MAX_POSE_RANK = 10; - static const int MAX_POSE_BLOCKS = 10; - - static const int MNB_RECOVERY_QUORUM_TOTAL = 10; - static const int MNB_RECOVERY_QUORUM_REQUIRED = 6; - static const int MNB_RECOVERY_MAX_ASK_ENTRIES = 10; - static const int MNB_RECOVERY_WAIT_SECONDS = 60; - static const int MNB_RECOVERY_RETRY_SECONDS = 3 * 60 * 60; - - // critical section to protect the inner data structures mutable CCriticalSection cs; - // Keep track of current block height - int nCachedBlockHeight; - // map to hold all MNs std::map mapMasternodes; - // who's asked for the Masternode list and the last time - std::map mAskedUsForMasternodeList; - // who we asked for the Masternode list and the last time - std::map mWeAskedForMasternodeList; - // which Masternodes we've asked for - std::map > mWeAskedForMasternodeListEntry; - - // who we asked for the masternode verification - std::map mWeAskedForVerification; - - // these maps are used for masternode recovery from MASTERNODE_NEW_START_REQUIRED state - std::map > > mMnbRecoveryRequests; - std::map > mMnbRecoveryGoodReplies; - std::list< std::pair > listScheduledMnbRequestConnections; - std::map > > mapPendingMNB; - std::map > mapPendingMNV; - CCriticalSection cs_mapPendingMNV; - - /// Set when masternodes are added, cleared when CGovernanceManager is notified - bool fMasternodesAdded; - - /// Set when masternodes are removed, cleared when CGovernanceManager is notified - bool fMasternodesRemoved; std::vector vecDirtyGovernanceObjectHashes; - int64_t nLastSentinelPingTime; - - friend class CMasternodeSync; /// Find an entry CMasternode* Find(const COutPoint& outpoint); bool GetMasternodeScores(const uint256& nBlockHash, score_pair_vec_t& vecMasternodeScoresRet); - void SyncSingle(CNode* pnode, const COutPoint& outpoint, CConnman& connman); - void SyncAll(CNode* pnode, CConnman& connman); - - void PushDsegInvs(CNode* pnode, const CMasternode& mn); - public: - // Keep track of all broadcasts I've seen - std::map > mapSeenMasternodeBroadcast; - // Keep track of all pings I've seen - std::map mapSeenMasternodePing; - // Keep track of all verifications I've seen - std::map mapSeenMasternodeVerification; // keep track of dsq count to prevent masternodes from gaming privatesend queue int64_t nDsqCount; @@ -115,16 +59,8 @@ public: } READWRITE(mapMasternodes); - READWRITE(mAskedUsForMasternodeList); - READWRITE(mWeAskedForMasternodeList); - READWRITE(mWeAskedForMasternodeListEntry); - READWRITE(mMnbRecoveryRequests); - READWRITE(mMnbRecoveryGoodReplies); - READWRITE(nLastSentinelPingTime); READWRITE(nDsqCount); - READWRITE(mapSeenMasternodeBroadcast); - READWRITE(mapSeenMasternodePing); if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { Clear(); } @@ -132,90 +68,25 @@ public: CMasternodeMan(); - /// Add an entry - bool Add(CMasternode &mn); - - /// Ask (source) node for mnb - void AskForMN(CNode *pnode, const COutPoint& outpoint, CConnman& connman); - - bool PoSeBan(const COutPoint &outpoint); bool IsValidForMixingTxes(const COutPoint &outpoint); bool AllowMixing(const COutPoint &outpoint); bool DisallowMixing(const COutPoint &outpoint); int64_t GetLastDsq(const COutPoint &outpoint); - /// Check all Masternodes - void Check(); - - /// Check all Masternodes and remove inactive - void CheckAndRemove(CConnman& connman); /// This is dummy overload to be used for dumping/loading mncache.dat void CheckAndRemove() {} - void AddDeterministicMasternodes(); - void RemoveNonDeterministicMasternodes(); - /// Clear Masternode vector void Clear(); - /// Count Masternodes filtered by nProtocolVersion. - /// Masternode nProtocolVersion should match or be above the one specified in param here. - int CountMasternodes(int nProtocolVersion = -1); - /// Count enabled Masternodes filtered by nProtocolVersion. - /// Masternode nProtocolVersion should match or be above the one specified in param here. - int CountEnabled(int nProtocolVersion = -1); - - /// Count Masternodes by network type - NET_IPV4, NET_IPV6, NET_TOR - // int CountByIP(int nNetworkType); - - void DsegUpdate(CNode* pnode, CConnman& connman); - - /// Versions of Find that are safe to use from outside the class - bool Get(const COutPoint& outpoint, CMasternode& masternodeRet); - bool Has(const COutPoint& outpoint); - - bool GetMasternodeInfo(const uint256& proTxHash, masternode_info_t& mnInfoRet); - bool GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet); - bool GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_info_t& mnInfoRet); - bool GetMasternodeInfo(const CScript& payee, masternode_info_t& mnInfoRet); - - /// Find an entry in the masternode list that is next to be paid - bool GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet); - /// Same as above but use current block height - bool GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet); - - std::map GetFullMasternodeMap(); - bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0); bool GetMasternodeRank(const COutPoint &outpoint, int& nRankRet, int nBlockHeight = -1, int nMinProtocol = 0); bool GetMasternodeRank(const COutPoint &outpoint, int& nRankRet, uint256& blockHashRet, int nBlockHeight = -1, int nMinProtocol = 0); void ProcessMasternodeConnections(CConnman& connman); - std::pair > PopScheduledMnbRequestConnection(); - void ProcessPendingMnbRequests(CConnman& connman); - - void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); - - void DoFullVerificationStep(CConnman& connman); - void CheckSameAddr(); - bool CheckVerifyRequestAddr(const CAddress& addr, CConnman& connman); - void PrepareVerifyRequest(const CAddress& addr, CConnman& connman); - void ProcessPendingMnvRequests(CConnman& connman); - void SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv, CConnman& connman); - void ProcessVerifyReply(CNode* pnode, CMasternodeVerification& mnv); - void ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerification& mnv); - - /// Return the number of (unique) Masternodes - int size() { return mapMasternodes.size(); } std::string ToString() const; - /// Perform complete check and only then update masternode list and maps using provided CMasternodeBroadcast - bool CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBroadcast mnb, int& nDos, CConnman& connman); - bool IsMnbRecoveryRequested(const uint256& hash) { return mMnbRecoveryRequests.count(hash); } - - void UpdateLastPaid(const CBlockIndex* pindex); - void AddDirtyGovernanceObjectHash(const uint256& nHash) { LOCK(cs); @@ -230,26 +101,9 @@ public: return vecTmp; } - bool IsSentinelPingActive(); - void UpdateLastSentinelPingTime(); bool AddGovernanceVote(const COutPoint& outpoint, uint256 nGovernanceObjectHash); void RemoveGovernanceObject(uint256 nGovernanceObjectHash); - void CheckMasternode(const CKeyID& keyIDOperator, bool fForce); - - bool IsMasternodePingedWithin(const COutPoint& outpoint, int nSeconds, int64_t nTimeToCheckAt = -1); - void SetMasternodeLastPing(const COutPoint& outpoint, const CMasternodePing& mnp); - - void UpdatedBlockTip(const CBlockIndex *pindex); - - void WarnMasternodeDaemonUpdates(); - - /** - * Called to notify CGovernanceManager that the masternode index has been updated. - * Must be called while not holding the CMasternodeMan::cs mutex - */ - void NotifyMasternodeUpdates(CConnman& connman, bool forceAddedChecks = false, bool forceRemovedChecks = false); - void DoMaintenance(CConnman &connman); }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 57e2d445a8..c5ce2c00aa 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -940,21 +940,6 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) return sporkManager.GetSporkByHash(inv.hash, spork); } - case MSG_MASTERNODE_PAYMENT_VOTE: - return mnpayments.mapMasternodePaymentVotes.count(inv.hash); - - case MSG_MASTERNODE_PAYMENT_BLOCK: - { - BlockMap::iterator mi = mapBlockIndex.find(inv.hash); - return mi != mapBlockIndex.end() && mnpayments.mapMasternodeBlocks.find(mi->second->nHeight) != mnpayments.mapMasternodeBlocks.end(); - } - - case MSG_MASTERNODE_ANNOUNCE: - return mnodeman.mapSeenMasternodeBroadcast.count(inv.hash) && !mnodeman.IsMnbRecoveryRequested(inv.hash); - - case MSG_MASTERNODE_PING: - return mnodeman.mapSeenMasternodePing.count(inv.hash); - case MSG_DSTX: { return static_cast(CPrivateSend::GetDSTX(inv.hash)); } @@ -963,9 +948,6 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) case MSG_GOVERNANCE_OBJECT_VOTE: return ! governance.ConfirmInventoryRequest(inv); - case MSG_MASTERNODE_VERIFY: - return mnodeman.mapSeenMasternodeVerification.count(inv.hash); - case MSG_QUORUM_FINAL_COMMITMENT: return llmq::quorumBlockProcessor->HasMinableCommitment(inv.hash); case MSG_QUORUM_DUMMY_COMMITMENT: @@ -1188,51 +1170,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } - if (!push && inv.type == MSG_MASTERNODE_PAYMENT_VOTE) { - if (!deterministicMNManager->IsDIP3Active()) { - if (mnpayments.HasVerifiedPaymentVote(inv.hash)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTVOTE, mnpayments.mapMasternodePaymentVotes[inv.hash])); - push = true; - } - } - } - - if (!push && inv.type == MSG_MASTERNODE_PAYMENT_BLOCK) { - if (!deterministicMNManager->IsDIP3Active()) { - BlockMap::iterator mi = mapBlockIndex.find(inv.hash); - LOCK(cs_mapMasternodeBlocks); - if (mi != mapBlockIndex.end() && mnpayments.mapMasternodeBlocks.count(mi->second->nHeight)) { - BOOST_FOREACH(CMasternodePayee& payee, mnpayments.mapMasternodeBlocks[mi->second->nHeight].vecPayees) { - std::vector vecVoteHashes = payee.GetVoteHashes(); - BOOST_FOREACH(uint256& hash, vecVoteHashes) { - if(mnpayments.HasVerifiedPaymentVote(hash)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTVOTE, mnpayments.mapMasternodePaymentVotes[hash])); - } - } - } - push = true; - } - } - } - - if (!push && inv.type == MSG_MASTERNODE_ANNOUNCE) { - if (!deterministicMNManager->IsDIP3Active()) { - if (mnodeman.mapSeenMasternodeBroadcast.count(inv.hash)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNANNOUNCE, mnodeman.mapSeenMasternodeBroadcast[inv.hash].second)); - push = true; - } - } - } - - if (!push && inv.type == MSG_MASTERNODE_PING) { - if (!deterministicMNManager->IsDIP3Active()) { - if (mnodeman.mapSeenMasternodePing.count(inv.hash)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNPING, mnodeman.mapSeenMasternodePing[inv.hash])); - push = true; - } - } - } - if (!push && inv.type == MSG_DSTX) { CPrivateSendBroadcastTx dstx = CPrivateSend::GetDSTX(inv.hash); if(dstx) { @@ -1278,13 +1215,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } - if (!push && inv.type == MSG_MASTERNODE_VERIFY) { - if(mnodeman.mapSeenMasternodeVerification.count(inv.hash)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNVERIFY, mnodeman.mapSeenMasternodeVerification[inv.hash])); - push = true; - } - } - if (!push && (inv.type == MSG_QUORUM_FINAL_COMMITMENT)) { llmq::CFinalCommitment o; if (llmq::quorumBlockProcessor->GetMinableCommitmentByHash(inv.hash, o)) { @@ -1796,20 +1726,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } else { - static std::set legacyMNObjs = { - MSG_MASTERNODE_PAYMENT_VOTE, - MSG_MASTERNODE_PAYMENT_BLOCK, - MSG_MASTERNODE_ANNOUNCE, - MSG_MASTERNODE_PING, - MSG_MASTERNODE_VERIFY, - }; static std::set allowWhileInIBDObjs = { MSG_SPORK }; - if (legacyMNObjs.count(inv.type) && deterministicMNManager->IsDIP3Active()) { - LogPrint("net", "ignoring (%s) inv of legacy type %d peer=%d\n", inv.hash.ToString(), inv.type, pfrom->id); - continue; - } pfrom->AddInventoryKnown(inv); if (fBlocksOnly) { @@ -2973,8 +2892,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr privateSendClient.ProcessMessage(pfrom, strCommand, vRecv, connman); #endif // ENABLE_WALLET privateSendServer.ProcessMessage(pfrom, strCommand, vRecv, connman); - mnodeman.ProcessMessage(pfrom, strCommand, vRecv, connman); - mnpayments.ProcessMessage(pfrom, strCommand, vRecv, connman); instantsend.ProcessMessage(pfrom, strCommand, vRecv, connman); sporkManager.ProcessSpork(pfrom, strCommand, vRecv, connman); masternodeSync.ProcessMessage(pfrom, strCommand, vRecv); diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 5088cda586..1e54ded04f 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -713,7 +713,7 @@ void CPrivateSendClientManager::AddSkippedDenom(const CAmount& nDenomValue) bool CPrivateSendClientManager::WaitForAnotherBlock() { - if (!masternodeSync.IsMasternodeListSynced()) + if (!masternodeSync.IsBlockchainSynced()) return true; if (fPrivateSendMultiSession) @@ -802,7 +802,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool if (fMasternodeMode) return false; // no client-side mixing on masternodes if (nState != POOL_STATE_IDLE) return false; - if (!masternodeSync.IsMasternodeListSynced()) { + if (!masternodeSync.IsBlockchainSynced()) { strAutoDenomResult = _("Can't mix while sync in progress."); return false; } @@ -939,7 +939,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool if (fMasternodeMode) return false; // no client-side mixing on masternodes if (!fEnablePrivateSend) return false; - if (!masternodeSync.IsMasternodeListSynced()) { + if (!masternodeSync.IsBlockchainSynced()) { strAutoDenomResult = _("Can't mix while sync in progress."); return false; } diff --git a/src/privatesend.cpp b/src/privatesend.cpp index da06c49ab9..c620b7a739 100644 --- a/src/privatesend.cpp +++ b/src/privatesend.cpp @@ -36,14 +36,7 @@ bool CPrivateSendEntry::AddScriptSig(const CTxIn& txin) uint256 CPrivateSendQueue::GetSignatureHash() const { - // Remove after migration to 70211 - { - masternode_info_t mnInfo; - mnodeman.GetMasternodeInfo(masternodeOutpoint, mnInfo); - return SerializeHash(*this, SER_GETHASH, mnInfo.nProtocolVersion); - } - // END remove, replace with the code below - // return SerializeHash(*this); + return SerializeHash(*this); } bool CPrivateSendQueue::Sign() @@ -476,7 +469,7 @@ void CPrivateSend::CheckDSTXes(int nHeight) void CPrivateSend::UpdatedBlockTip(const CBlockIndex* pindex) { - if (pindex && !fLiteMode && masternodeSync.IsMasternodeListSynced()) { + if (pindex && !fLiteMode && masternodeSync.IsBlockchainSynced()) { CheckDSTXes(pindex->nHeight); } } diff --git a/src/protocol.cpp b/src/protocol.cpp index fa1ccaf9ce..9a4b661e17 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -44,17 +44,6 @@ const char *TXLOCKREQUEST="ix"; const char *TXLOCKVOTE="txlvote"; const char *SPORK="spork"; const char *GETSPORKS="getsporks"; -const char *MASTERNODEPAYMENTVOTE="mnw"; -const char *MASTERNODEPAYMENTBLOCK="mnwb"; -const char *MASTERNODEPAYMENTSYNC="mnget"; -const char *MNBUDGETSYNC="mnvs"; // deprecated since 12.1 -const char *MNBUDGETVOTE="mvote"; // deprecated since 12.1 -const char *MNBUDGETPROPOSAL="mprop"; // deprecated since 12.1 -const char *MNBUDGETFINAL="fbs"; // deprecated since 12.1 -const char *MNBUDGETFINALVOTE="fbvote"; // deprecated since 12.1 -const char *MNQUORUM="mn quorum"; // not implemented -const char *MNANNOUNCE="mnb"; -const char *MNPING="mnp"; const char *DSACCEPT="dsa"; const char *DSVIN="dsi"; const char *DSFINALTX="dsf"; @@ -63,12 +52,10 @@ const char *DSCOMPLETE="dsc"; const char *DSSTATUSUPDATE="dssu"; const char *DSTX="dstx"; const char *DSQUEUE="dsq"; -const char *DSEG="dseg"; const char *SYNCSTATUSCOUNT="ssc"; const char *MNGOVERNANCESYNC="govsync"; const char *MNGOVERNANCEOBJECT="govobj"; const char *MNGOVERNANCEOBJECTVOTE="govobjvote"; -const char *MNVERIFY="mnv"; const char *GETMNLISTDIFF="getmnlistd"; const char *MNLISTDIFF="mnlistdiff"; const char *QFCOMMITMENT="qfcommit"; @@ -87,19 +74,19 @@ static const char* ppszTypeName[] = NetMsgType::TXLOCKREQUEST, NetMsgType::TXLOCKVOTE, NetMsgType::SPORK, - NetMsgType::MASTERNODEPAYMENTVOTE, - NetMsgType::MASTERNODEPAYMENTBLOCK, // reusing, was MNSCANERROR previousely, was NOT used in 12.0, we need this for inv - NetMsgType::MNBUDGETVOTE, // deprecated since 12.1 - NetMsgType::MNBUDGETPROPOSAL, // deprecated since 12.1 - NetMsgType::MNBUDGETFINAL, // deprecated since 12.1 - NetMsgType::MNBUDGETFINALVOTE, // deprecated since 12.1 - NetMsgType::MNQUORUM, // not implemented - NetMsgType::MNANNOUNCE, - NetMsgType::MNPING, + "unused inv type 7", + "unused inv type 8", + "unused inv type 9", + "unused inv type 10", + "unused inv type 11", + "unused inv type 12", + "unused inv type 13", + "unused inv type 14", + "unused inv type 15", NetMsgType::DSTX, NetMsgType::MNGOVERNANCEOBJECT, NetMsgType::MNGOVERNANCEOBJECTVOTE, - NetMsgType::MNVERIFY, + "unused inv type 19", "compact block", // Should never occur NetMsgType::QFCOMMITMENT, NetMsgType::QDCOMMITMENT, @@ -142,11 +129,6 @@ const static std::string allNetMessageTypes[] = { NetMsgType::TXLOCKVOTE, NetMsgType::SPORK, NetMsgType::GETSPORKS, - NetMsgType::MASTERNODEPAYMENTVOTE, - // NetMsgType::MASTERNODEPAYMENTBLOCK, // there is no message for this, only inventory - NetMsgType::MASTERNODEPAYMENTSYNC, - NetMsgType::MNANNOUNCE, - NetMsgType::MNPING, NetMsgType::DSACCEPT, NetMsgType::DSVIN, NetMsgType::DSFINALTX, @@ -155,12 +137,10 @@ const static std::string allNetMessageTypes[] = { NetMsgType::DSSTATUSUPDATE, NetMsgType::DSTX, NetMsgType::DSQUEUE, - NetMsgType::DSEG, NetMsgType::SYNCSTATUSCOUNT, NetMsgType::MNGOVERNANCESYNC, NetMsgType::MNGOVERNANCEOBJECT, NetMsgType::MNGOVERNANCEOBJECTVOTE, - NetMsgType::MNVERIFY, NetMsgType::GETMNLISTDIFF, NetMsgType::MNLISTDIFF, NetMsgType::QFCOMMITMENT, diff --git a/src/protocol.h b/src/protocol.h index ba1b25c456..2d2e85e840 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -250,10 +250,6 @@ extern const char *TXLOCKREQUEST; extern const char *TXLOCKVOTE; extern const char *SPORK; extern const char *GETSPORKS; -extern const char *MASTERNODEPAYMENTVOTE; -extern const char *MASTERNODEPAYMENTSYNC; -extern const char *MNANNOUNCE; -extern const char *MNPING; extern const char *DSACCEPT; extern const char *DSVIN; extern const char *DSFINALTX; @@ -262,12 +258,10 @@ extern const char *DSCOMPLETE; extern const char *DSSTATUSUPDATE; extern const char *DSTX; extern const char *DSQUEUE; -extern const char *DSEG; extern const char *SYNCSTATUSCOUNT; extern const char *MNGOVERNANCESYNC; extern const char *MNGOVERNANCEOBJECT; extern const char *MNGOVERNANCEOBJECTVOTE; -extern const char *MNVERIFY; extern const char *GETMNLISTDIFF; extern const char *MNLISTDIFF; extern const char *QFCOMMITMENT; @@ -358,19 +352,11 @@ enum GetDataMsg { MSG_TXLOCK_REQUEST = 4, MSG_TXLOCK_VOTE = 5, MSG_SPORK = 6, - MSG_MASTERNODE_PAYMENT_VOTE = 7, - MSG_MASTERNODE_PAYMENT_BLOCK = 8, // reusing, was MSG_MASTERNODE_SCANNING_ERROR previousely, was NOT used in 12.0 - MSG_BUDGET_VOTE = 9, // deprecated since 12.1 - MSG_BUDGET_PROPOSAL = 10, // deprecated since 12.1 - MSG_BUDGET_FINALIZED = 11, // deprecated since 12.1 - MSG_BUDGET_FINALIZED_VOTE = 12, // deprecated since 12.1 - MSG_MASTERNODE_QUORUM = 13, // not implemented - MSG_MASTERNODE_ANNOUNCE = 14, - MSG_MASTERNODE_PING = 15, + /* 7 - 15 were used in old Dash versions and were mainly budget and MN broadcast/ping related*/ MSG_DSTX = 16, MSG_GOVERNANCE_OBJECT = 17, MSG_GOVERNANCE_OBJECT_VOTE = 18, - MSG_MASTERNODE_VERIFY = 19, + /* 19 was used for MSG_MASTERNODE_VERIFY and is not supported anymore */ // Nodes may always request a MSG_CMPCT_BLOCK in a getdata, however, // MSG_CMPCT_BLOCK should not appear in any invs except as a part of getdata. MSG_CMPCT_BLOCK = 20, //!< Defined in BIP152 diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index eff7235187..2803c05429 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -419,8 +419,6 @@ void BitcoinGUI::createActions() openRepairAction->setStatusTip(tr("Show wallet repair options")); openConfEditorAction = new QAction(QIcon(":/icons/" + theme + "/edit"), tr("Open Wallet &Configuration File"), this); openConfEditorAction->setStatusTip(tr("Open configuration file")); - openMNConfEditorAction = new QAction(QIcon(":/icons/" + theme + "/edit"), tr("Open &Masternode Configuration File"), this); - openMNConfEditorAction->setStatusTip(tr("Open Masternode configuration file")); showBackupsAction = new QAction(QIcon(":/icons/" + theme + "/browse"), tr("Show Automatic &Backups"), this); showBackupsAction->setStatusTip(tr("Show automatically created wallet backups")); // initially disable the debug window menu items @@ -463,7 +461,6 @@ void BitcoinGUI::createActions() // Open configs and backup folder from menu connect(openConfEditorAction, SIGNAL(triggered()), this, SLOT(showConfEditor())); - connect(openMNConfEditorAction, SIGNAL(triggered()), this, SLOT(showMNConfEditor())); connect(showBackupsAction, SIGNAL(triggered()), this, SLOT(showBackups())); // Get restart command-line parameters and handle restart @@ -541,7 +538,6 @@ void BitcoinGUI::createMenuBar() tools->addAction(openRepairAction); tools->addSeparator(); tools->addAction(openConfEditorAction); - tools->addAction(openMNConfEditorAction); tools->addAction(showBackupsAction); } @@ -756,7 +752,6 @@ void BitcoinGUI::createIconMenu(QMenu *pmenu) pmenu->addAction(openRepairAction); pmenu->addSeparator(); pmenu->addAction(openConfEditorAction); - pmenu->addAction(openMNConfEditorAction); pmenu->addAction(showBackupsAction); #ifndef Q_OS_MAC // This is built-in on Mac pmenu->addSeparator(); @@ -837,11 +832,6 @@ void BitcoinGUI::showConfEditor() GUIUtil::openConfigfile(); } -void BitcoinGUI::showMNConfEditor() -{ - GUIUtil::openMNConfigfile(); -} - void BitcoinGUI::showBackups() { GUIUtil::showBackups(); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index e03648b951..f1e21f26f4 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -121,7 +121,6 @@ private: QAction *openPeersAction; QAction *openRepairAction; QAction *openConfEditorAction; - QAction *openMNConfEditorAction; QAction *showBackupsAction; QAction *openAction; QAction *showHelpMessageAction; @@ -248,8 +247,6 @@ private Q_SLOTS: /** Open external (default) editor with dash.conf */ void showConfEditor(); - /** Open external (default) editor with masternode.conf */ - void showMNConfEditor(); /** Show folder with wallet backups in default file browser */ void showBackups(); diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index 5b08ca36e3..d588b3724c 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -26,7 +26,6 @@ #include "paymentserver.h" #include "walletmodel.h" #endif -#include "masternodeconfig.h" #include "init.h" #include "rpc/server.h" @@ -684,14 +683,6 @@ int main(int argc, char *argv[]) initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); #ifdef ENABLE_WALLET - /// 7a. parse masternode.conf - std::string strErr; - if(!masternodeConfig.read(strErr)) { - QMessageBox::critical(0, QObject::tr("Dash Core"), - QObject::tr("Error reading masternode configuration file: %1").arg(strErr.c_str())); - return EXIT_FAILURE; - } - /// 8. URI IPC sending // - Do this early as we don't want to bother initializing if we are just calling IPC // - Do this *after* setting up the data directory, as the data directory hash is used in the name diff --git a/src/qt/forms/masternodelist.ui b/src/qt/forms/masternodelist.ui index f479a608d9..03c08266d6 100644 --- a/src/qt/forms/masternodelist.ui +++ b/src/qt/forms/masternodelist.ui @@ -49,295 +49,12 @@ 0 - - - My Masternodes - - - - - - 0 - - - - - 0 - - - - - Note: Status of your masternodes in local wallet can potentially be slightly incorrect.<br />Always wait for wallet to sync additional data and then double check from another node<br />if your masternode should be running but you still do not see "ENABLED" in "Status" field. - - - - - - - - - - 695 - 0 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - true - - - true - - - - Alias - - - - - Address - - - - - Protocol - - - - - Status - - - - - Active - - - - - Last Seen - - - - - Payee - - - - - - - - 0 - - - - - S&tart alias - - - - - - - Start &all - - - - - - - Start &MISSING - - - - - - - &Update status - - - - - - - Show additional Masternode information - - - Show &Info... - - - - - - - Status will be updated automatically in (sec): - - - - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - All Masternodes - - - - - - 0 - - - - - Filter List: - - - - - - - Filter masternode list - - - - - - - Qt::Horizontal - - - - 10 - 20 - - - - - - - - Node Count: - - - - - - - 0 - - - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SelectRows - - - QAbstractItemView::NoSelection - - - true - - - true - - - - Address - - - - - Protocol - - - - - Status - - - - - Active - - - - - Last Seen - - - - - Payee - - - - - - - - <html><head/><body><p>Note: This list represents the legacy and non-deterministic masternode list. It is only active as long as DIP3 has not been fully activated. After SPORK15 activation, this list will be empty.</p></body></html> - - - Qt::AutoText - - - true - - - - - DIP3 Masternodes - + 0 @@ -385,7 +102,7 @@ - + QAbstractItemView::NoEditTriggers @@ -447,19 +164,6 @@ - - - - <html><head/><body><p>Note: This list is not active yet and only for informational purposes. The network is still running in compatibility mode, which means that the non-deterministic masternode list is still active. Only after SPORK15 activation, this list will become the active one. Also, the values in the payment related fields are not used at the moment, but still updated for every block. Please ignore this until SPORK15 activation.</p></body></html> - - - Qt::AutoText - - - true - - - diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 0486f121fc..31aab8ff2d 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -447,15 +447,6 @@ void openConfigfile() QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); } -void openMNConfigfile() -{ - boost::filesystem::path pathConfig = GetMasternodeConfigFile(); - - /* Open masternode.conf with the associated application */ - if (boost::filesystem::exists(pathConfig)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); -} - void showBackups() { boost::filesystem::path backupsDir = GetBackupsDir(); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index c69b1ad251..9360d8e85f 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -117,9 +117,6 @@ namespace GUIUtil // Open dash.conf void openConfigfile(); - // Open masternode.conf - void openMNConfigfile(); - // Browse backup folder void showBackups(); diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index b8b086613c..30a165f481 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -7,7 +7,6 @@ #include "guiutil.h" #include "init.h" #include "masternode-sync.h" -#include "masternodeconfig.h" #include "masternodeman.h" #include "netbase.h" #include "qrdialog.h" @@ -40,15 +39,8 @@ MasternodeList::MasternodeList(const PlatformStyle* platformStyle, QWidget* pare { ui->setupUi(this); - ui->startButton->setEnabled(false); - - int columnAliasWidth = 100; int columnAddressWidth = 200; - int columnProtocolWidth = 60; int columnStatusWidth = 80; - int columnActiveWidth = 130; - int columnLastSeenWidth = 130; - int columnPoSeScoreWidth = 80; int columnRegisteredWidth = 80; int columnLastPaidWidth = 80; @@ -56,19 +48,6 @@ MasternodeList::MasternodeList(const PlatformStyle* platformStyle, QWidget* pare int columnPayeeWidth = 130; int columnOperatorRewardWidth = 130; - ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth); - ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth); - ui->tableWidgetMyMasternodes->setColumnWidth(2, columnProtocolWidth); - ui->tableWidgetMyMasternodes->setColumnWidth(3, columnStatusWidth); - ui->tableWidgetMyMasternodes->setColumnWidth(4, columnActiveWidth); - ui->tableWidgetMyMasternodes->setColumnWidth(5, columnLastSeenWidth); - - ui->tableWidgetMasternodes->setColumnWidth(0, columnAddressWidth); - ui->tableWidgetMasternodes->setColumnWidth(1, columnProtocolWidth); - ui->tableWidgetMasternodes->setColumnWidth(2, columnStatusWidth); - ui->tableWidgetMasternodes->setColumnWidth(3, columnActiveWidth); - ui->tableWidgetMasternodes->setColumnWidth(4, columnLastSeenWidth); - ui->tableWidgetMasternodesDIP3->setColumnWidth(0, columnAddressWidth); ui->tableWidgetMasternodesDIP3->setColumnWidth(1, columnStatusWidth); ui->tableWidgetMasternodesDIP3->setColumnWidth(2, columnPoSeScoreWidth); @@ -83,16 +62,8 @@ MasternodeList::MasternodeList(const PlatformStyle* platformStyle, QWidget* pare ui->tableWidgetMasternodesDIP3->insertColumn(8); ui->tableWidgetMasternodesDIP3->setColumnHidden(8, true); - ui->tableWidgetMyMasternodes->setContextMenuPolicy(Qt::CustomContextMenu); ui->tableWidgetMasternodesDIP3->setContextMenuPolicy(Qt::CustomContextMenu); - QAction* startAliasAction = new QAction(tr("Start alias"), this); - contextMenu = new QMenu(); - contextMenu->addAction(startAliasAction); - connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); - connect(ui->tableWidgetMyMasternodes, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(on_QRButton_clicked())); - connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked())); - QAction* copyProTxHashAction = new QAction(tr("Copy ProTx Hash"), this); QAction* copyCollateralOutpointAction = new QAction(tr("Copy Collateral Outpoint"), this); contextMenuDIP3 = new QMenu(); @@ -104,16 +75,11 @@ MasternodeList::MasternodeList(const PlatformStyle* platformStyle, QWidget* pare connect(copyCollateralOutpointAction, SIGNAL(triggered()), this, SLOT(copyCollateralOutpoint_clicked())); timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(updateNodeList())); - connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList())); connect(timer, SIGNAL(timeout()), this, SLOT(updateDIP3List())); timer->start(1000); - fFilterUpdated = false; fFilterUpdatedDIP3 = false; - nTimeFilterUpdated = GetTime(); nTimeFilterUpdatedDIP3 = GetTime(); - updateNodeList(); updateDIP3List(); } @@ -136,279 +102,18 @@ void MasternodeList::setWalletModel(WalletModel* model) this->walletModel = model; } -void MasternodeList::showContextMenu(const QPoint& point) -{ - QTableWidgetItem* item = ui->tableWidgetMyMasternodes->itemAt(point); - if (item) contextMenu->exec(QCursor::pos()); -} - void MasternodeList::showContextMenuDIP3(const QPoint& point) { QTableWidgetItem* item = ui->tableWidgetMasternodesDIP3->itemAt(point); if (item) contextMenuDIP3->exec(QCursor::pos()); } -void MasternodeList::StartAlias(std::string strAlias) -{ - std::string strStatusHtml; - strStatusHtml += "
Alias: " + strAlias; - - for (const auto& mne : masternodeConfig.getEntries()) { - if (mne.getAlias() == strAlias) { - std::string strError; - CMasternodeBroadcast mnb; - - bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb); - - int nDoS; - if (fSuccess && !mnodeman.CheckMnbAndUpdateMasternodeList(NULL, mnb, nDoS, *g_connman)) { - strError = "Failed to verify MNB"; - fSuccess = false; - } - - if (fSuccess) { - strStatusHtml += "
Successfully started masternode."; - mnodeman.NotifyMasternodeUpdates(*g_connman); - } else { - strStatusHtml += "
Failed to start masternode.
Error: " + strError; - } - break; - } - } - strStatusHtml += "
"; - - QMessageBox msg; - msg.setText(QString::fromStdString(strStatusHtml)); - msg.exec(); - - updateMyNodeList(true); -} - -void MasternodeList::StartAll(std::string strCommand) -{ - int nCountSuccessful = 0; - int nCountFailed = 0; - std::string strFailedHtml; - - for (const auto& mne : masternodeConfig.getEntries()) { - std::string strError; - CMasternodeBroadcast mnb; - - int32_t nOutputIndex = 0; - if (!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) { - continue; - } - - COutPoint outpoint = COutPoint(uint256S(mne.getTxHash()), nOutputIndex); - - if (strCommand == "start-missing" && mnodeman.Has(outpoint)) continue; - - bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb); - - int nDoS; - if (fSuccess && !mnodeman.CheckMnbAndUpdateMasternodeList(NULL, mnb, nDoS, *g_connman)) { - strError = "Failed to verify MNB"; - fSuccess = false; - } - - if (fSuccess) { - nCountSuccessful++; - mnodeman.NotifyMasternodeUpdates(*g_connman); - } else { - nCountFailed++; - strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError; - } - } - - std::string returnObj; - returnObj = strprintf("Successfully started %d masternodes, failed to start %d, total %d", nCountSuccessful, nCountFailed, nCountFailed + nCountSuccessful); - if (nCountFailed > 0) { - returnObj += strFailedHtml; - } - - QMessageBox msg; - msg.setText(QString::fromStdString(returnObj)); - msg.exec(); - - updateMyNodeList(true); -} - -void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, const COutPoint& outpoint) -{ - bool fOldRowFound = false; - int nNewRow = 0; - - for (int i = 0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) { - if (ui->tableWidgetMyMasternodes->item(i, 0)->text() == strAlias) { - fOldRowFound = true; - nNewRow = i; - break; - } - } - - if (nNewRow == 0 && !fOldRowFound) { - nNewRow = ui->tableWidgetMyMasternodes->rowCount(); - ui->tableWidgetMyMasternodes->insertRow(nNewRow); - } - - masternode_info_t infoMn; - bool fFound = mnodeman.GetMasternodeInfo(outpoint, infoMn); - - QTableWidgetItem* aliasItem = new QTableWidgetItem(strAlias); - QTableWidgetItem* addrItem = new QTableWidgetItem(fFound ? QString::fromStdString(infoMn.addr.ToString()) : strAddr); - QTableWidgetItem* protocolItem = new QTableWidgetItem(QString::number(fFound ? infoMn.nProtocolVersion : -1)); - QTableWidgetItem* statusItem = new QTableWidgetItem(QString::fromStdString(fFound ? CMasternode::StateToString(infoMn.nActiveState) : "MISSING")); - QTableWidgetItem* activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(fFound ? (infoMn.nTimeLastPing - infoMn.sigTime) : 0))); - QTableWidgetItem* lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M", - fFound ? infoMn.nTimeLastPing + GetOffsetFromUtc() : 0))); - QTableWidgetItem* pubkeyItem = new QTableWidgetItem(QString::fromStdString(fFound ? CBitcoinAddress(infoMn.keyIDCollateralAddress).ToString() : "")); - - ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem); - ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem); - ui->tableWidgetMyMasternodes->setItem(nNewRow, 2, protocolItem); - ui->tableWidgetMyMasternodes->setItem(nNewRow, 3, statusItem); - ui->tableWidgetMyMasternodes->setItem(nNewRow, 4, activeSecondsItem); - ui->tableWidgetMyMasternodes->setItem(nNewRow, 5, lastSeenItem); - ui->tableWidgetMyMasternodes->setItem(nNewRow, 6, pubkeyItem); -} - -void MasternodeList::updateMyNodeList(bool fForce) -{ - if (ShutdownRequested()) { - return; - } - if (deterministicMNManager->IsDIP3Active()) { - return; - } - - TRY_LOCK(cs_mymnlist, fLockAcquired); - if (!fLockAcquired) return; - - static int64_t nTimeMyListUpdated = 0; - - // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds, - // this update still can be triggered manually at any time via button click - int64_t nSecondsTillUpdate = nTimeMyListUpdated + MY_MASTERNODELIST_UPDATE_SECONDS - GetTime(); - ui->secondsLabel->setText(QString::number(nSecondsTillUpdate)); - - if (nSecondsTillUpdate > 0 && !fForce) return; - nTimeMyListUpdated = GetTime(); - - // Find selected row - QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel(); - QModelIndexList selected = selectionModel->selectedRows(); - int nSelectedRow = selected.count() ? selected.at(0).row() : 0; - - ui->tableWidgetMyMasternodes->setSortingEnabled(false); - for (const auto& mne : masternodeConfig.getEntries()) { - int32_t nOutputIndex = 0; - if (!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) { - continue; - } - - updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), COutPoint(uint256S(mne.getTxHash()), nOutputIndex)); - } - ui->tableWidgetMyMasternodes->selectRow(nSelectedRow); - ui->tableWidgetMyMasternodes->setSortingEnabled(true); - - // reset "timer" - ui->secondsLabel->setText("0"); -} - -void MasternodeList::updateNodeList() -{ - if (ShutdownRequested()) { - return; - } - - if (deterministicMNManager->IsDIP3Active()) { - // we misuse the fact that updateNodeList is called regularely here and remove both tabs - if (ui->tabWidget->indexOf(ui->tabDIP3Masternodes) != 0) { - // remove "My Masternode" and "All Masternodes" tabs - ui->tabWidget->removeTab(0); - ui->tabWidget->removeTab(0); - } - return; - } - - TRY_LOCK(cs_mnlist, fLockAcquired); - if (!fLockAcquired) return; - - static int64_t nTimeListUpdated = GetTime(); - - // to prevent high cpu usage update only once in MASTERNODELIST_UPDATE_SECONDS seconds - // or MASTERNODELIST_FILTER_COOLDOWN_SECONDS seconds after filter was last changed - int64_t nSecondsToWait = fFilterUpdated - ? nTimeFilterUpdated - GetTime() + MASTERNODELIST_FILTER_COOLDOWN_SECONDS - : nTimeListUpdated - GetTime() + MASTERNODELIST_UPDATE_SECONDS; - - if (fFilterUpdated) { - ui->countLabel->setText(QString::fromStdString(strprintf("Please wait... %d", nSecondsToWait))); - } - if (nSecondsToWait > 0) return; - - nTimeListUpdated = GetTime(); - fFilterUpdated = false; - - QString strToFilter; - ui->countLabel->setText("Updating..."); - ui->tableWidgetMasternodes->setSortingEnabled(false); - ui->tableWidgetMasternodes->clearContents(); - ui->tableWidgetMasternodes->setRowCount(0); - - if (deterministicMNManager->IsDIP3Active()) { - ui->countLabel->setText(QString::number(0)); - return; - } - - int offsetFromUtc = GetOffsetFromUtc(); - - std::map mapMasternodes = mnodeman.GetFullMasternodeMap(); - - for (const auto& mnpair : mapMasternodes) { - CMasternode mn = mnpair.second; - // populate list - // Address, Protocol, Status, Active Seconds, Last Seen, Pub Key - QTableWidgetItem* addressItem = new QTableWidgetItem(QString::fromStdString(mn.addr.ToString())); - QTableWidgetItem* protocolItem = new QTableWidgetItem(QString::number(mn.nProtocolVersion)); - QTableWidgetItem* statusItem = new QTableWidgetItem(QString::fromStdString(mn.GetStatus())); - QTableWidgetItem* activeSecondsItem = new QTableWidgetItem(QString::fromStdString(DurationToDHMS(mn.lastPing.sigTime - mn.sigTime))); - QTableWidgetItem* lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M", mn.lastPing.sigTime + offsetFromUtc))); - QTableWidgetItem* pubkeyItem = new QTableWidgetItem(QString::fromStdString(CBitcoinAddress(mn.keyIDCollateralAddress).ToString())); - - if (strCurrentFilter != "") { - strToFilter = addressItem->text() + " " + - protocolItem->text() + " " + - statusItem->text() + " " + - activeSecondsItem->text() + " " + - lastSeenItem->text() + " " + - pubkeyItem->text(); - if (!strToFilter.contains(strCurrentFilter)) continue; - } - - ui->tableWidgetMasternodes->insertRow(0); - ui->tableWidgetMasternodes->setItem(0, 0, addressItem); - ui->tableWidgetMasternodes->setItem(0, 1, protocolItem); - ui->tableWidgetMasternodes->setItem(0, 2, statusItem); - ui->tableWidgetMasternodes->setItem(0, 3, activeSecondsItem); - ui->tableWidgetMasternodes->setItem(0, 4, lastSeenItem); - ui->tableWidgetMasternodes->setItem(0, 5, pubkeyItem); - } - - ui->countLabel->setText(QString::number(ui->tableWidgetMasternodes->rowCount())); - ui->tableWidgetMasternodes->setSortingEnabled(true); -} - void MasternodeList::updateDIP3List() { if (ShutdownRequested()) { return; } - if (deterministicMNManager->IsDIP3Active()) { - ui->dip3NoteLabel->setVisible(false); - } - TRY_LOCK(cs_dip3list, fLockAcquired); if (!fLockAcquired) return; @@ -421,7 +126,7 @@ void MasternodeList::updateDIP3List() : nTimeListUpdated - GetTime() + MASTERNODELIST_UPDATE_SECONDS; if (fFilterUpdatedDIP3) { - ui->countLabel->setText(QString::fromStdString(strprintf("Please wait... %d", nSecondsToWait))); + ui->countLabelDIP3->setText(QString::fromStdString(strprintf("Please wait... %d", nSecondsToWait))); } if (nSecondsToWait > 0) return; @@ -510,14 +215,6 @@ void MasternodeList::updateDIP3List() ui->tableWidgetMasternodesDIP3->setSortingEnabled(true); } -void MasternodeList::on_filterLineEdit_textChanged(const QString& strFilterIn) -{ - strCurrentFilter = strFilterIn; - nTimeFilterUpdated = GetTime(); - fFilterUpdated = true; - ui->countLabel->setText(QString::fromStdString(strprintf("Please wait... %d", MASTERNODELIST_FILTER_COOLDOWN_SECONDS))); -} - void MasternodeList::on_filterLineEditDIP3_textChanged(const QString& strFilterIn) { strCurrentFilterDIP3 = strFilterIn; @@ -526,181 +223,6 @@ void MasternodeList::on_filterLineEditDIP3_textChanged(const QString& strFilterI ui->countLabelDIP3->setText(QString::fromStdString(strprintf("Please wait... %d", MASTERNODELIST_FILTER_COOLDOWN_SECONDS))); } -void MasternodeList::on_startButton_clicked() -{ - std::string strAlias; - { - LOCK(cs_mymnlist); - // Find selected node alias - QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel(); - QModelIndexList selected = selectionModel->selectedRows(); - - if (selected.count() == 0) return; - - QModelIndex index = selected.at(0); - int nSelectedRow = index.row(); - strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString(); - } - - // Display message box - QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"), - tr("Are you sure you want to start masternode %1?").arg(QString::fromStdString(strAlias)), - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); - - if (retval != QMessageBox::Yes) return; - - WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); - - if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForMixingOnly) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); - - if (!ctx.isValid()) return; // Unlock wallet was cancelled - - StartAlias(strAlias); - return; - } - - StartAlias(strAlias); -} - -void MasternodeList::on_startAllButton_clicked() -{ - // Display message box - QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm all masternodes start"), - tr("Are you sure you want to start ALL masternodes?"), - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); - - if (retval != QMessageBox::Yes) return; - - WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); - - if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForMixingOnly) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); - - if (!ctx.isValid()) return; // Unlock wallet was cancelled - - StartAll(); - return; - } - - StartAll(); -} - -void MasternodeList::on_startMissingButton_clicked() -{ - if (!masternodeSync.IsMasternodeListSynced()) { - QMessageBox::critical(this, tr("Command is not available right now"), - tr("You can't use this command until masternode list is synced")); - return; - } - - // Display message box - QMessageBox::StandardButton retval = QMessageBox::question(this, - tr("Confirm missing masternodes start"), - tr("Are you sure you want to start MISSING masternodes?"), - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); - - if (retval != QMessageBox::Yes) return; - - WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); - - if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForMixingOnly) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); - - if (!ctx.isValid()) return; // Unlock wallet was cancelled - - StartAll("start-missing"); - return; - } - - StartAll("start-missing"); -} - -void MasternodeList::on_tableWidgetMyMasternodes_itemSelectionChanged() -{ - if (ui->tableWidgetMyMasternodes->selectedItems().count() > 0) { - ui->startButton->setEnabled(true); - } -} - -void MasternodeList::on_UpdateButton_clicked() -{ - updateMyNodeList(true); -} - -void MasternodeList::on_QRButton_clicked() -{ - std::string strAlias; - { - LOCK(cs_mymnlist); - // Find selected node alias - QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel(); - QModelIndexList selected = selectionModel->selectedRows(); - - if (selected.count() == 0) return; - - QModelIndex index = selected.at(0); - int nSelectedRow = index.row(); - strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString(); - } - - ShowQRCode(strAlias); -} - -void MasternodeList::ShowQRCode(std::string strAlias) -{ - if (!walletModel || !walletModel->getOptionsModel()) return; - - // Get private key for this alias - std::string strMNPrivKey = ""; - std::string strCollateral = ""; - std::string strIP = ""; - CMasternode mn; - bool fFound = false; - - for (const auto& mne : masternodeConfig.getEntries()) { - if (strAlias == mne.getAlias()) { - strMNPrivKey = mne.getPrivKey(); - strCollateral = mne.getTxHash() + "-" + mne.getOutputIndex(); - strIP = mne.getIp(); - fFound = mnodeman.Get(COutPoint(uint256S(mne.getTxHash()), atoi(mne.getOutputIndex())), mn); - break; - } - } - - // Title of popup window - QString strWindowtitle = tr("Additional information for Masternode %1").arg(QString::fromStdString(strAlias)); - - // Title above QR-Code - QString strQRCodeTitle = tr("Masternode Private Key"); - - // Create dialog text as HTML - QString strHTML = ""; - strHTML += "" + tr("Alias") + ": " + GUIUtil::HtmlEscape(strAlias) + "
"; - strHTML += "" + tr("Private Key") + ": " + GUIUtil::HtmlEscape(strMNPrivKey) + "
"; - strHTML += "" + tr("Collateral") + ": " + GUIUtil::HtmlEscape(strCollateral) + "
"; - strHTML += "" + tr("IP") + ": " + GUIUtil::HtmlEscape(strIP) + "
"; - if (fFound) { - strHTML += "" + tr("Protocol") + ": " + QString::number(mn.nProtocolVersion) + "
"; - strHTML += "" + tr("Version") + ": " + (mn.lastPing.nDaemonVersion > DEFAULT_DAEMON_VERSION ? GUIUtil::HtmlEscape(FormatVersion(mn.lastPing.nDaemonVersion)) : tr("Unknown")) + "
"; - strHTML += "" + tr("Sentinel") + ": " + (mn.lastPing.nSentinelVersion > DEFAULT_SENTINEL_VERSION ? GUIUtil::HtmlEscape(SafeIntVersionToString(mn.lastPing.nSentinelVersion)) : tr("Unknown")) + "
"; - strHTML += "" + tr("Status") + ": " + GUIUtil::HtmlEscape(CMasternode::StateToString(mn.nActiveState)) + "
"; - strHTML += "" + tr("Payee") + ": " + GUIUtil::HtmlEscape(CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString()) + "
"; - strHTML += "" + tr("Active") + ": " + GUIUtil::HtmlEscape(DurationToDHMS(mn.lastPing.sigTime - mn.sigTime)) + "
"; - strHTML += "" + tr("Last Seen") + ": " + GUIUtil::HtmlEscape(DateTimeStrFormat("%Y-%m-%d %H:%M", mn.lastPing.sigTime + GetOffsetFromUtc())) + "
"; - } - - // Open QR dialog - QRDialog* dialog = new QRDialog(this); - dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setModel(walletModel->getOptionsModel()); - dialog->setInfo(strWindowtitle, QString::fromStdString(strMNPrivKey), strHTML, strQRCodeTitle); - dialog->show(); -} - CDeterministicMNCPtr MasternodeList::GetSelectedDIP3MN() { std::string strProTxHash; diff --git a/src/qt/masternodelist.h b/src/qt/masternodelist.h index 5532c94e66..0c19830eaf 100644 --- a/src/qt/masternodelist.h +++ b/src/qt/masternodelist.h @@ -12,7 +12,6 @@ #include #include -#define MY_MASTERNODELIST_UPDATE_SECONDS 60 #define MASTERNODELIST_UPDATE_SECONDS 15 #define MASTERNODELIST_FILTER_COOLDOWN_SECONDS 3 @@ -39,23 +38,14 @@ public: void setClientModel(ClientModel* clientModel); void setWalletModel(WalletModel* walletModel); - void ShowQRCode(std::string strAlias); - void StartAlias(std::string strAlias); - void StartAll(std::string strCommand = "start-all"); CDeterministicMNCPtr GetSelectedDIP3MN(); private: - QMenu* contextMenu; QMenu* contextMenuDIP3; - int64_t nTimeFilterUpdated; int64_t nTimeFilterUpdatedDIP3; - bool fFilterUpdated; bool fFilterUpdatedDIP3; public Q_SLOTS: - void updateMyMasternodeInfo(QString strAlias, QString strAddr, const COutPoint& outpoint); - void updateMyNodeList(bool fForce = false); - void updateNodeList(); void updateDIP3List(); Q_SIGNALS: @@ -67,29 +57,14 @@ private: ClientModel* clientModel; WalletModel* walletModel; - // Protects tableWidgetMasternodes - CCriticalSection cs_mnlist; - - // Protects tableWidgetMyMasternodes - CCriticalSection cs_mymnlist; - // Protects tableWidgetMasternodesDIP3 CCriticalSection cs_dip3list; - QString strCurrentFilter; QString strCurrentFilterDIP3; private Q_SLOTS: - void showContextMenu(const QPoint&); void showContextMenuDIP3(const QPoint&); - void on_filterLineEdit_textChanged(const QString& strFilterIn); void on_filterLineEditDIP3_textChanged(const QString& strFilterIn); - void on_QRButton_clicked(); - void on_startButton_clicked(); - void on_startAllButton_clicked(); - void on_startMissingButton_clicked(); - void on_tableWidgetMyMasternodes_itemSelectionChanged(); - void on_UpdateButton_clicked(); void extraInfoDIP3_clicked(); void copyProTxHash_clicked(); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 27b68fe2c0..5f53ab639d 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -23,7 +23,6 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" -#include "masternodeconfig.h" #include "privatesend-client.h" #endif @@ -93,9 +92,6 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("digits")) settings.setValue("digits", "2"); - if (!settings.contains("fShowMasternodesTab")) - settings.setValue("fShowMasternodesTab", masternodeConfig.getCount()); - // PrivateSend if (!settings.contains("fShowAdvancedPSUI")) settings.setValue("fShowAdvancedPSUI", false); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 16239a9476..8fe72c9c73 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -9,7 +9,6 @@ #include "bitcoingui.h" #include "clientmodel.h" #include "guiutil.h" -#include "masternodeconfig.h" #include "optionsmodel.h" #include "overviewpage.h" #include "platformstyle.h" diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 16ad1c891d..115d3b963e 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -14,7 +14,6 @@ #include "validation.h" #include "masternode.h" #include "masternode-sync.h" -#include "masternodeconfig.h" #include "masternodeman.h" #include "messagesigner.h" #include "rpc/server.h" @@ -264,7 +263,7 @@ UniValue gobject_submit(const JSONRPCRequest& request) auto mnList = deterministicMNManager->GetListAtChainTip(); bool fMnFound = mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint); - DBG( std::cout << "gobject: submit activeMasternodeInfo.keyIDOperator = " << activeMasternodeInfo.legacyKeyIDOperator.ToString() + DBG( std::cout << "gobject: submit activeMasternodeInfo.pubKeyOperator = " << (activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A") << ", outpoint = " << activeMasternodeInfo.outpoint.ToStringShort() << ", params.size() = " << request.params.size() << ", fMnFound = " << fMnFound << std::endl; ); @@ -314,11 +313,7 @@ UniValue gobject_submit(const JSONRPCRequest& request) if (govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) { if (fMnFound) { govobj.SetMasternodeOutpoint(activeMasternodeInfo.outpoint); - if (deterministicMNManager->IsDIP3Active()) { - govobj.Sign(*activeMasternodeInfo.blsKeyOperator); - } else { - govobj.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator); - } + govobj.Sign(*activeMasternodeInfo.blsKeyOperator); } else { LogPrintf("gobject(submit) -- Object submission rejected because node is not a masternode\n"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Only valid masternodes can submit this type of object"); @@ -947,9 +942,9 @@ UniValue gobject_getcurrentvotes(const JSONRPCRequest& request) " getcurrentvotes - Get only current (tallying) votes for a governance object hash (does not include old votes)\n" " list - List governance objects (can be filtered by signal and/or object type)\n" " diff - List differences since last diff\n" - " vote-alias - Vote on a governance object by masternode alias (using masternode.conf setup)\n" + " vote-alias - Vote on a governance object by masternode alias/proTxHash\n" " vote-conf - Vote on a governance object by masternode configured in dash.conf\n" - " vote-many - Vote on a governance object by all masternodes (using masternode.conf setup)\n" + " vote-many - Vote on a governance object by all masternodes for which the voting key is in the wallet\n" ); } @@ -1113,8 +1108,6 @@ UniValue getgovernanceinfo(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("governanceminquorum", Params().GetConsensus().nGovernanceMinQuorum)); - obj.push_back(Pair("masternodewatchdogmaxseconds", MASTERNODE_SENTINEL_PING_MAX_SECONDS)); - obj.push_back(Pair("sentinelpingmaxseconds", MASTERNODE_SENTINEL_PING_MAX_SECONDS)); obj.push_back(Pair("proposalfee", ValueFromAmount(GOVERNANCE_PROPOSAL_FEE_TX))); obj.push_back(Pair("superblockcycle", Params().GetConsensus().nSuperblockCycle)); obj.push_back(Pair("lastsuperblock", nLastSuperblock)); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 9bf61955c5..28cfeefdec 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -10,7 +10,6 @@ #include "validation.h" #include "masternode-payments.h" #include "masternode-sync.h" -#include "masternodeconfig.h" #include "masternodeman.h" #ifdef ENABLE_WALLET #include "privatesend-client.h" @@ -24,8 +23,6 @@ #include "evo/specialtx.h" #include "evo/deterministicmns.h" -#include "evo/deterministicmns.h" - #include #include #include @@ -149,7 +146,7 @@ void masternode_list_help() " payee - Print Dash address associated with a masternode (can be additionally filtered,\n" " partial match)\n" " pubKeyOperator - Print the masternode operator public key\n" - " status - Print masternode status: ENABLED / POSE_BAN / OUTPOINT_SPENT\n" + " status - Print masternode status: ENABLED / POSE_BANNED\n" " (can be additionally filtered, partial match)\n" ); } @@ -305,210 +302,6 @@ UniValue masternode_current(const JSONRPCRequest& request) } #ifdef ENABLE_WALLET -void masternode_start_alias_help() -{ - throw std::runtime_error( - "masternode start-alias \"alias\"\n" - "Start single remote masternode by assigned alias\n" - "\nArguments:\n" - "1. \"alias\" (string, required) The alias of the remote masternode configured in masternode.conf\n" - ); -} - -UniValue masternode_start_alias(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() < 2) - masternode_start_alias_help(); - if (deterministicMNManager->IsDIP3Active()) - throw JSONRPCError(RPC_MISC_ERROR, "start-alias is not supported when deterministic masternode list is active (DIP3)"); - - if (!EnsureWalletIsAvailable(request.fHelp)) - return NullUniValue; - - { - LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - } - - std::string strAlias = request.params[1].get_str(); - - bool fFound = false; - - UniValue statusObj(UniValue::VOBJ); - statusObj.push_back(Pair("alias", strAlias)); - - for (const auto& mne : masternodeConfig.getEntries()) { - if (mne.getAlias() == strAlias) { - fFound = true; - std::string strError; - CMasternodeBroadcast mnb; - - bool fResult = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb); - - int nDoS; - if (fResult && !mnodeman.CheckMnbAndUpdateMasternodeList(NULL, mnb, nDoS, *g_connman)) { - strError = "Failed to verify MNB"; - fResult = false; - } - - statusObj.push_back(Pair("result", fResult ? "successful" : "failed")); - if (!fResult) { - statusObj.push_back(Pair("errorMessage", strError)); - } - mnodeman.NotifyMasternodeUpdates(*g_connman); - break; - } - } - - if (!fFound) { - statusObj.push_back(Pair("result", "failed")); - statusObj.push_back(Pair("errorMessage", "Could not find alias in config. Verify with list-conf.")); - } - - return statusObj; -} - -void masternode_start_all_help() -{ - throw std::runtime_error( - "masternode start-all\n" - "Start remote masternodes configured in masternode.conf\n" - ); -} - -UniValue StartMasternodeList(const std::vector& entries) -{ - int nSuccessful = 0; - int nFailed = 0; - - UniValue resultsObj(UniValue::VOBJ); - - for (const auto& mne : entries) { - std::string strError; - CMasternodeBroadcast mnb; - - bool fResult = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb); - - int nDoS; - if (fResult && !mnodeman.CheckMnbAndUpdateMasternodeList(NULL, mnb, nDoS, *g_connman)) { - strError = "Failed to verify MNB"; - fResult = false; - } - - UniValue statusObj(UniValue::VOBJ); - statusObj.push_back(Pair("alias", mne.getAlias())); - statusObj.push_back(Pair("result", fResult ? "successful" : "failed")); - - if (fResult) { - nSuccessful++; - } else { - nFailed++; - statusObj.push_back(Pair("errorMessage", strError)); - } - - resultsObj.push_back(Pair("status", statusObj)); - } - mnodeman.NotifyMasternodeUpdates(*g_connman); - - UniValue returnObj(UniValue::VOBJ); - returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", nSuccessful, nFailed, nSuccessful + nFailed))); - returnObj.push_back(Pair("detail", resultsObj)); - - return returnObj; -} - -UniValue masternode_start_all(const JSONRPCRequest& request) -{ - if (request.fHelp) - masternode_start_all_help(); - if (deterministicMNManager->IsDIP3Active()) - throw JSONRPCError(RPC_MISC_ERROR, strprintf("start-all is not supported when deterministic masternode list is active (DIP3)")); - - if (!EnsureWalletIsAvailable(request.fHelp)) - return NullUniValue; - - { - LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - } - - return StartMasternodeList(masternodeConfig.getEntries()); -} - -void masternode_start_missing_help() -{ - throw std::runtime_error( - "masternode start-missing\n" - "Start not started remote masternodes configured in masternode.conf\n" - ); -} - -UniValue masternode_start_missing(const JSONRPCRequest& request) -{ - if (request.fHelp) - masternode_start_missing_help(); - - if (!EnsureWalletIsAvailable(request.fHelp)) - return NullUniValue; - - { - LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - } - - if (!masternodeSync.IsMasternodeListSynced()) { - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "You can't use this command until masternode list is synced"); - } - - std::vector entries; - for (const auto& mne : masternodeConfig.getEntries()) { - COutPoint outpoint = COutPoint(uint256S(mne.getTxHash()), (uint32_t)atoi(mne.getOutputIndex())); - CMasternode mn; - bool fFound = mnodeman.Get(outpoint, mn); - if (fFound) - entries.push_back(mne); - } - return StartMasternodeList(entries); -} - -void masternode_start_disabled_help() -{ - throw std::runtime_error( - "masternode start-disabled\n" - "Start not started and disabled remote masternodes configured in masternode.conf\n" - ); -} - -UniValue masternode_start_disabled(const JSONRPCRequest& request) -{ - if (request.fHelp) - masternode_start_disabled_help(); - - if (!EnsureWalletIsAvailable(request.fHelp)) - return NullUniValue; - - { - LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - } - - if (!masternodeSync.IsMasternodeListSynced()) { - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "You can't use this command until masternode list is synced"); - } - - std::vector entries; - for (const auto& mne : masternodeConfig.getEntries()) { - COutPoint outpoint = COutPoint(uint256S(mne.getTxHash()), (uint32_t)atoi(mne.getOutputIndex())); - CMasternode mn; - bool fFound = mnodeman.Get(outpoint, mn); - - if (fFound && mn.IsEnabled()) continue; - - entries.push_back(mne); - } - return StartMasternodeList(entries); -} - void masternode_outputs_help() { throw std::runtime_error( @@ -539,67 +332,6 @@ UniValue masternode_outputs(const JSONRPCRequest& request) #endif // ENABLE_WALLET -void masternode_genkey_help() -{ - throw std::runtime_error( - "masternode genkey (compressed)\n" - "Generate new masternodeprivkey\n" - "\nArguments:\n" - "1. compressed (boolean, optional, default=false) generate compressed privkey\n" - ); -} - -UniValue masternode_genkey(const JSONRPCRequest& request) -{ - if (request.fHelp) - masternode_genkey_help(); - - bool fCompressed = false; - if (request.params.size() > 1) { - fCompressed = ParseBoolV(request.params[1], "compressed"); - } - - CKey secret; - secret.MakeNewKey(fCompressed); - - return CBitcoinSecret(secret).ToString(); -} - -void masternode_list_conf_help() -{ - throw std::runtime_error( - "masternode list-conf\n" - "Print masternode.conf in JSON format\n" - ); -} - -UniValue masternode_list_conf(const JSONRPCRequest& request) -{ - if (request.fHelp) - masternode_list_conf_help(); - - UniValue resultObj(UniValue::VOBJ); - - for (const auto& mne : masternodeConfig.getEntries()) { - COutPoint outpoint = COutPoint(uint256S(mne.getTxHash()), (uint32_t)atoi(mne.getOutputIndex())); - CMasternode mn; - bool fFound = mnodeman.Get(outpoint, mn); - - std::string strStatus = fFound ? mn.GetStatus() : "MISSING"; - - UniValue mnObj(UniValue::VOBJ); - mnObj.push_back(Pair("alias", mne.getAlias())); - mnObj.push_back(Pair("address", mne.getIp())); - mnObj.push_back(Pair("privateKey", mne.getPrivKey())); - mnObj.push_back(Pair("txHash", mne.getTxHash())); - mnObj.push_back(Pair("outputIndex", mne.getOutputIndex())); - mnObj.push_back(Pair("status", strStatus)); - resultObj.push_back(Pair("masternode", mnObj)); - } - - return resultObj; -} - void masternode_status_help() { throw std::runtime_error( @@ -622,26 +354,18 @@ UniValue masternode_status(const JSONRPCRequest& request) mnObj.push_back(Pair("outpoint", activeMasternodeInfo.outpoint.ToStringShort())); mnObj.push_back(Pair("service", activeMasternodeInfo.service.ToString())); - if (deterministicMNManager->IsDIP3Active()) { - auto dmn = activeMasternodeManager->GetDMN(); - if (dmn) { - mnObj.push_back(Pair("proTxHash", dmn->proTxHash.ToString())); - mnObj.push_back(Pair("collateralHash", dmn->collateralOutpoint.hash.ToString())); - mnObj.push_back(Pair("collateralIndex", (int)dmn->collateralOutpoint.n)); - UniValue stateObj; - dmn->pdmnState->ToJson(stateObj); - mnObj.push_back(Pair("dmnState", stateObj)); - } - mnObj.push_back(Pair("state", activeMasternodeManager->GetStateString())); - mnObj.push_back(Pair("status", activeMasternodeManager->GetStatus())); - } else { - CMasternode mn; - if (mnodeman.Get(activeMasternodeInfo.outpoint, mn)) { - mnObj.push_back(Pair("payee", CBitcoinAddress(mn.keyIDCollateralAddress).ToString())); - } - - mnObj.push_back(Pair("status", legacyActiveMasternodeManager.GetStatus())); + auto dmn = activeMasternodeManager->GetDMN(); + if (dmn) { + mnObj.push_back(Pair("proTxHash", dmn->proTxHash.ToString())); + mnObj.push_back(Pair("collateralHash", dmn->collateralOutpoint.hash.ToString())); + mnObj.push_back(Pair("collateralIndex", (int)dmn->collateralOutpoint.n)); + UniValue stateObj; + dmn->pdmnState->ToJson(stateObj); + mnObj.push_back(Pair("dmnState", stateObj)); } + mnObj.push_back(Pair("state", activeMasternodeManager->GetStateString())); + mnObj.push_back(Pair("status", activeMasternodeManager->GetStatus())); + return mnObj; } @@ -693,38 +417,6 @@ UniValue masternode_winners(const JSONRPCRequest& request) return obj; } -void masternode_check_help() -{ - throw std::runtime_error( - "masternode check\n" - "Force check all masternodes and remove invalid ones\n" - ); -} - -UniValue masternode_check(const JSONRPCRequest& request) -{ - if (request.fHelp) - masternode_check_help(); - - int countBeforeCheck = mnodeman.CountMasternodes(); - int countEnabledBeforeCheck = mnodeman.CountEnabled(); - - mnodeman.CheckAndRemove(*g_connman); - - int countAfterCheck = mnodeman.CountMasternodes(); - int countEnabledAfterCheck = mnodeman.CountEnabled(); - int removedCount = std::max(0, countBeforeCheck - countAfterCheck); - int removedEnabledCount = std::max(0, countEnabledBeforeCheck - countEnabledAfterCheck); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("removedTotalCount", removedCount)); - obj.push_back(Pair("removedEnabledCount", removedEnabledCount)); - obj.push_back(Pair("totalCount", countAfterCheck)); - obj.push_back(Pair("enabledCount", countEnabledAfterCheck)); - - return obj; -} - [[ noreturn ]] void masternode_help() { throw std::runtime_error( @@ -733,18 +425,13 @@ UniValue masternode_check(const JSONRPCRequest& request) "\nArguments:\n" "1. \"command\" (string or set of strings, required) The command to execute\n" "\nAvailable commands:\n" - " check - Force check all masternodes and remove invalid ones\n" " count - Get information about number of masternodes (DEPRECATED options: 'total', 'ps', 'enabled', 'qualify', 'all')\n" " current - Print info on current masternode winner to be paid the next block (calculated locally)\n" - " genkey - Generate new masternodeprivkey, optional param: 'compressed' (boolean, optional, default=false) generate compressed privkey\n" #ifdef ENABLE_WALLET " outputs - Print masternode compatible outputs\n" - " start-alias - Start single remote masternode by assigned alias configured in masternode.conf\n" - " start- - Start remote masternodes configured in masternode.conf (: 'all', 'missing', 'disabled')\n" #endif // ENABLE_WALLET " status - Print masternode status information\n" " list - Print list of all known masternodes (see masternodelist for more info)\n" - " list-conf - Print masternode.conf in JSON format\n" " winner - Print info on next masternode winner to vote for\n" " winners - Print list of masternode winners\n" ); @@ -776,20 +463,6 @@ UniValue masternode(const JSONRPCRequest& request) return masternode_current(request); } else if (strCommand == "winner") { return masternode_winner(request); -#ifdef ENABLE_WALLET - } else if (strCommand == "start-alias") { - return masternode_start_alias(request); - } else if (strCommand == "start-all") { - return masternode_start_all(request); - } else if (strCommand == "start-missing") { - return masternode_start_missing(request); - } else if (strCommand == "start-disabled") { - return masternode_start_disabled(request); -#endif // ENABLE_WALLET - } else if (strCommand == "genkey") { - return masternode_genkey(request); - } else if (strCommand == "list-conf") { - return masternode_list_conf(request); #ifdef ENABLE_WALLET } else if (strCommand == "outputs") { return masternode_outputs(request); @@ -798,8 +471,6 @@ UniValue masternode(const JSONRPCRequest& request) return masternode_status(request); } else if (strCommand == "winners") { return masternode_winners(request); - } else if (strCommand == "check") { - return masternode_check(request); } else { masternode_help(); } @@ -825,15 +496,6 @@ UniValue masternodelist(const JSONRPCRequest& request) masternode_list_help(); } - if (strMode == "full" || strMode == "json" || strMode == "lastpaidtime" || strMode == "lastpaidblock") { - CBlockIndex* pindex = NULL; - { - LOCK(cs_main); - pindex = chainActive.Tip(); - } - mnodeman.UpdateLastPaid(pindex); - } - UniValue obj(UniValue::VOBJ); auto mnList = deterministicMNManager->GetListAtChainTip(); @@ -940,278 +602,12 @@ UniValue masternodelist(const JSONRPCRequest& request) return obj; } -bool DecodeHexVecMnb(std::vector& vecMnb, std::string strHexMnb) { - - if (!IsHex(strHexMnb)) - return false; - - std::vector mnbData(ParseHex(strHexMnb)); - CDataStream ssData(mnbData, SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> vecMnb; - } catch (const std::exception&) { - return false; - } - - return true; -} - -UniValue masternodebroadcast(const JSONRPCRequest& request) -{ - std::string strCommand; - if (request.params.size() >= 1) - strCommand = request.params[0].get_str(); - - if (request.fHelp || - ( -#ifdef ENABLE_WALLET - strCommand != "create-alias" && strCommand != "create-all" && -#endif // ENABLE_WALLET - strCommand != "decode" && strCommand != "relay")) - throw std::runtime_error( - "masternodebroadcast \"command\"...\n" - "Set of commands to create and relay masternode broadcast messages\n" - "\nArguments:\n" - "1. \"command\" (string or set of strings, required) The command to execute\n" - "\nAvailable commands:\n" -#ifdef ENABLE_WALLET - " create-alias - Create single remote masternode broadcast message by assigned alias configured in masternode.conf\n" - " create-all - Create remote masternode broadcast messages for all masternodes configured in masternode.conf\n" -#endif // ENABLE_WALLET - " decode - Decode masternode broadcast message\n" - " relay - Relay masternode broadcast message to the network\n" - ); - -#ifdef ENABLE_WALLET - if (strCommand == "create-alias") { - if (!EnsureWalletIsAvailable(request.fHelp)) - return NullUniValue; - - // wait for reindex and/or import to finish - if (fImporting || fReindex) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish"); - - if (request.params.size() < 2) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Please specify an alias"); - - { - LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - } - - bool fFound = false; - std::string strAlias = request.params[1].get_str(); - - UniValue statusObj(UniValue::VOBJ); - std::vector vecMnb; - - statusObj.push_back(Pair("alias", strAlias)); - - for (const auto& mne : masternodeConfig.getEntries()) { - if (mne.getAlias() == strAlias) { - fFound = true; - std::string strError; - CMasternodeBroadcast mnb; - - bool fResult = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb, true); - - statusObj.push_back(Pair("result", fResult ? "successful" : "failed")); - if (fResult) { - vecMnb.push_back(mnb); - CDataStream ssVecMnb(SER_NETWORK, PROTOCOL_VERSION); - ssVecMnb << vecMnb; - statusObj.push_back(Pair("hex", HexStr(ssVecMnb))); - } else { - statusObj.push_back(Pair("errorMessage", strError)); - } - break; - } - } - - if (!fFound) { - statusObj.push_back(Pair("result", "not found")); - statusObj.push_back(Pair("errorMessage", "Could not find alias in config. Verify with list-conf.")); - } - - return statusObj; - - } - - if (strCommand == "create-all") { - if (!EnsureWalletIsAvailable(request.fHelp)) - return NullUniValue; - - // wait for reindex and/or import to finish - if (fImporting || fReindex) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish"); - - { - LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); - } - - int nSuccessful = 0; - int nFailed = 0; - - UniValue resultsObj(UniValue::VOBJ); - std::vector vecMnb; - - for (const auto& mne : masternodeConfig.getEntries()) { - std::string strError; - CMasternodeBroadcast mnb; - - bool fResult = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb, true); - - UniValue statusObj(UniValue::VOBJ); - statusObj.push_back(Pair("alias", mne.getAlias())); - statusObj.push_back(Pair("result", fResult ? "successful" : "failed")); - - if (fResult) { - nSuccessful++; - vecMnb.push_back(mnb); - } else { - nFailed++; - statusObj.push_back(Pair("errorMessage", strError)); - } - - resultsObj.push_back(Pair("status", statusObj)); - } - - CDataStream ssVecMnb(SER_NETWORK, PROTOCOL_VERSION); - ssVecMnb << vecMnb; - UniValue returnObj(UniValue::VOBJ); - returnObj.push_back(Pair("overall", strprintf("Successfully created broadcast messages for %d masternodes, failed to create %d, total %d", nSuccessful, nFailed, nSuccessful + nFailed))); - returnObj.push_back(Pair("detail", resultsObj)); - returnObj.push_back(Pair("hex", HexStr(ssVecMnb.begin(), ssVecMnb.end()))); - - return returnObj; - } -#endif // ENABLE_WALLET - - if (strCommand == "decode") { - if (request.params.size() != 2) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'masternodebroadcast decode \"hexstring\"'"); - - std::vector vecMnb; - - if (!DecodeHexVecMnb(vecMnb, request.params[1].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed"); - - int nSuccessful = 0; - int nFailed = 0; - int nDos = 0; - UniValue returnObj(UniValue::VOBJ); - - for (const auto& mnb : vecMnb) { - UniValue resultObj(UniValue::VOBJ); - - if (mnb.CheckSignature(nDos)) { - nSuccessful++; - resultObj.push_back(Pair("outpoint", mnb.outpoint.ToStringShort())); - resultObj.push_back(Pair("addr", mnb.addr.ToString())); - resultObj.push_back(Pair("keyIDCollateralAddress", CBitcoinAddress(mnb.keyIDCollateralAddress).ToString())); - resultObj.push_back(Pair("keyIDMasternode", CBitcoinAddress(mnb.legacyKeyIDOperator).ToString())); - resultObj.push_back(Pair("vchSig", EncodeBase64(&mnb.vchSig[0], mnb.vchSig.size()))); - resultObj.push_back(Pair("sigTime", mnb.sigTime)); - resultObj.push_back(Pair("protocolVersion", mnb.nProtocolVersion)); - resultObj.push_back(Pair("nLastDsq", mnb.nLastDsq)); - - UniValue lastPingObj(UniValue::VOBJ); - lastPingObj.push_back(Pair("outpoint", mnb.lastPing.masternodeOutpoint.ToStringShort())); - lastPingObj.push_back(Pair("blockHash", mnb.lastPing.blockHash.ToString())); - lastPingObj.push_back(Pair("sigTime", mnb.lastPing.sigTime)); - lastPingObj.push_back(Pair("vchSig", EncodeBase64(&mnb.lastPing.vchSig[0], mnb.lastPing.vchSig.size()))); - - resultObj.push_back(Pair("lastPing", lastPingObj)); - } else { - nFailed++; - resultObj.push_back(Pair("errorMessage", "Masternode broadcast signature verification failed")); - } - - returnObj.push_back(Pair(mnb.GetHash().ToString(), resultObj)); - } - - returnObj.push_back(Pair("overall", strprintf("Successfully decoded broadcast messages for %d masternodes, failed to decode %d, total %d", nSuccessful, nFailed, nSuccessful + nFailed))); - - return returnObj; - } - - if (strCommand == "relay") { - if (request.params.size() < 2 || request.params.size() > 3) - throw JSONRPCError(RPC_INVALID_PARAMETER, "masternodebroadcast relay \"hexstring\"\n" - "\nArguments:\n" - "1. \"hex\" (string, required) Broadcast messages hex string\n"); - - std::vector vecMnb; - - if (!DecodeHexVecMnb(vecMnb, request.params[1].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed"); - - int nSuccessful = 0; - int nFailed = 0; - UniValue returnObj(UniValue::VOBJ); - - // verify all signatures first, bailout if any of them broken - for (const auto& mnb : vecMnb) { - UniValue resultObj(UniValue::VOBJ); - - resultObj.push_back(Pair("outpoint", mnb.outpoint.ToStringShort())); - resultObj.push_back(Pair("addr", mnb.addr.ToString())); - - int nDos = 0; - bool fResult; - if (mnb.CheckSignature(nDos)) { - fResult = mnodeman.CheckMnbAndUpdateMasternodeList(NULL, mnb, nDos, *g_connman); - mnodeman.NotifyMasternodeUpdates(*g_connman); - } else fResult = false; - - if (fResult) { - nSuccessful++; - resultObj.push_back(Pair(mnb.GetHash().ToString(), "successful")); - } else { - nFailed++; - resultObj.push_back(Pair("errorMessage", "Masternode broadcast signature verification failed")); - } - - returnObj.push_back(Pair(mnb.GetHash().ToString(), resultObj)); - } - - returnObj.push_back(Pair("overall", strprintf("Successfully relayed broadcast messages for %d masternodes, failed to relay %d, total %d", nSuccessful, nFailed, nSuccessful + nFailed))); - - return returnObj; - } - - return NullUniValue; -} - -UniValue sentinelping(const JSONRPCRequest& request) -{ - if (request.fHelp || request.params.size() != 1) { - throw std::runtime_error( - "sentinelping version\n" - "\nSentinel ping.\n" - "\nArguments:\n" - "1. version (string, required) Sentinel version in the form \"x.x.x\"\n" - "\nResult:\n" - "state (boolean) Ping result\n" - "\nExamples:\n" - + HelpExampleCli("sentinelping", "1.0.2") - + HelpExampleRpc("sentinelping", "1.0.2") - ); - } - - legacyActiveMasternodeManager.UpdateSentinelPing(StringVersionToInt(request.params[0].get_str())); - return true; -} - static const CRPCCommand commands[] = { // category name actor (function) okSafe argNames // --------------------- ------------------------ ----------------------- ------ ---------- { "dash", "masternode", &masternode, true, {} }, { "dash", "masternodelist", &masternodelist, true, {} }, - { "dash", "masternodebroadcast", &masternodebroadcast, true, {} }, { "dash", "getpoolinfo", &getpoolinfo, true, {} }, - { "dash", "sentinelping", &sentinelping, true, {} }, #ifdef ENABLE_WALLET { "dash", "privatesend", &privatesend, false, {} }, #endif // ENABLE_WALLET diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 49c5e500a1..b42acb1e17 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -500,7 +500,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) // when enforcement is on we need information about a masternode payee or otherwise our block is going to be orphaned by the network std::vector voutMasternodePayments; if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) - && !masternodeSync.IsWinnersListSynced() + && !masternodeSync.IsBlockchainSynced() && !mnpayments.GetBlockTxOuts(chainActive.Height() + 1, 0, voutMasternodePayments)) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Dash Core is downloading masternode winners..."); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 1c321b6ca0..8799a7959f 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -157,8 +157,6 @@ UniValue mnsync(const JSONRPCRequest& request) objStatus.push_back(Pair("AssetStartTime", masternodeSync.GetAssetStartTime())); objStatus.push_back(Pair("Attempt", masternodeSync.GetAttempt())); objStatus.push_back(Pair("IsBlockchainSynced", masternodeSync.IsBlockchainSynced())); - objStatus.push_back(Pair("IsMasternodeListSynced", masternodeSync.IsMasternodeListSynced())); - objStatus.push_back(Pair("IsWinnersListSynced", masternodeSync.IsWinnersListSynced())); objStatus.push_back(Pair("IsSynced", masternodeSync.IsSynced())); objStatus.push_back(Pair("IsFailed", masternodeSync.IsFailed())); return objStatus; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 2cfe0da152..8e25611d7d 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -62,7 +62,7 @@ struct { {0, 0x4000b6b6}, {0, 0x6000ea25}, {0, 0x400989d9}, {0, 0xc000877f}, {0, 0x6000d17c}, {0, 0xc0009228}, {0, 0x4002827f}, {0, 0x80056a85}, {0, 0x40045af7}, {0, 0x6000df7a}, {0, 0xe00131a1}, {0, 0x40021386}, - {0, 0xa00891b5}, {0, 0x60007854} + {0, 0xa00891b5}, {0, 0x60007854}, {0, 0x60021730} }; CBlockIndex CreateBlockIndex(int nHeight) @@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { const CChainParams& chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; - std::unique_ptr pblocktemplate; + std::unique_ptr pblocktemplate, pemptyblocktemplate; CMutableTransaction tx,tx2; CScript script; uint256 hash; @@ -205,19 +205,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) LOCK(cs_main); fCheckpointsEnabled = false; - // force UpdatedBlockTip to initialize nCachedBlockHeight - mnpayments.UpdatedBlockTip(chainActive.Tip(), *connman); - // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pemptyblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) int baseheight = 0; std::vector txFirst; - for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) - { - CBlock *pblock = &pblocktemplate->block; // pointer for convenience + + auto createAndProcessEmptyBlock = [&]() { + int i = chainActive.Height(); + CBlock *pblock = &pemptyblocktemplate->block; // pointer for convenience pblock->nVersion = 2; pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1; CMutableTransaction txCoinbase(*pblock->vtx[0]); @@ -233,9 +231,21 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txFirst.push_back(pblock->vtx[0]); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; + + // This will usually succeed in the first round as we take the nonce from blockinfo + // It's however usefull when adding new blocks with unknown nonces (you should add the found block to blockinfo) + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) { + pblock->nNonce++; + } + std::shared_ptr shared_pblock = std::make_shared(*pblock); BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL)); pblock->hashPrevBlock = pblock->GetHash(); + }; + + for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo) - 1; ++i) + { + createAndProcessEmptyBlock(); } // Just to make sure we can still make simple blocks @@ -485,13 +495,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // However if we advance height by 1 and time by 512, all of them should be mined for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast - chainActive.Tip()->nHeight++; + + // Mine an empty block + createAndProcessEmptyBlock(); + SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5); - chainActive.Tip()->nHeight--; + CValidationState state; + InvalidateBlock(state, chainparams, chainActive.Tip()); + SetMockTime(0); mempool.clear(); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 5b99cec558..8c00487925 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -343,11 +343,4 @@ BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) BOOST_CHECK_EQUAL(result[2].get_int(), 9); } -BOOST_AUTO_TEST_CASE(rpc_sentinel_ping) -{ - BOOST_CHECK_NO_THROW(CallRPC("sentinelping 1.0.2")); - BOOST_CHECK_THROW(CallRPC("sentinelping"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("sentinelping 2"), std::bad_cast); -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util.cpp b/src/util.cpp index 036479f8ae..a024178892 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -641,14 +641,6 @@ boost::filesystem::path GetConfigFile(const std::string& confPath) return pathConfigFile; } -boost::filesystem::path GetMasternodeConfigFile() -{ - boost::filesystem::path pathConfigFile(GetArg("-mnconf", "masternode.conf")); - if (!pathConfigFile.is_complete()) - pathConfigFile = GetDataDir() / pathConfigFile; - return pathConfigFile; -} - void ReadConfigFile(const std::string& confPath) { boost::filesystem::ifstream streamConfig(GetConfigFile(confPath)); diff --git a/src/util.h b/src/util.h index b28bb5d945..323ade47cc 100644 --- a/src/util.h +++ b/src/util.h @@ -137,7 +137,6 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); boost::filesystem::path GetBackupsDir(); void ClearDatadirCache(); boost::filesystem::path GetConfigFile(const std::string& confPath); -boost::filesystem::path GetMasternodeConfigFile(); #ifndef WIN32 boost::filesystem::path GetPidFile(); void CreatePidFile(const boost::filesystem::path &path, pid_t pid); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 26b08647da..86f374ec16 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -29,6 +29,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.NotifyGovernanceObject.connect(boost::bind(&CValidationInterface::NotifyGovernanceObject, pwalletIn, _1)); g_signals.NotifyGovernanceVote.connect(boost::bind(&CValidationInterface::NotifyGovernanceVote, pwalletIn, _1)); g_signals.NotifyInstantSendDoubleSpendAttempt.connect(boost::bind(&CValidationInterface::NotifyInstantSendDoubleSpendAttempt, pwalletIn, _1, _2)); + g_signals.NotifyMasternodeListChanged.connect(boost::bind(&CValidationInterface::NotifyMasternodeListChanged, pwalletIn, _1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { @@ -48,6 +49,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.NotifyGovernanceObject.disconnect(boost::bind(&CValidationInterface::NotifyGovernanceObject, pwalletIn, _1)); g_signals.NotifyGovernanceVote.disconnect(boost::bind(&CValidationInterface::NotifyGovernanceVote, pwalletIn, _1)); g_signals.NotifyInstantSendDoubleSpendAttempt.disconnect(boost::bind(&CValidationInterface::NotifyInstantSendDoubleSpendAttempt, pwalletIn, _1, _2)); + g_signals.NotifyMasternodeListChanged.disconnect(boost::bind(&CValidationInterface::NotifyMasternodeListChanged, pwalletIn, _1)); } void UnregisterAllValidationInterfaces() { @@ -67,4 +69,5 @@ void UnregisterAllValidationInterfaces() { g_signals.NotifyGovernanceObject.disconnect_all_slots(); g_signals.NotifyGovernanceVote.disconnect_all_slots(); g_signals.NotifyInstantSendDoubleSpendAttempt.disconnect_all_slots(); + g_signals.NotifyMasternodeListChanged.disconnect_all_slots(); } diff --git a/src/validationinterface.h b/src/validationinterface.h index f5f5df31c0..78dafba43a 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -20,6 +20,7 @@ class CValidationInterface; class CValidationState; class CGovernanceVote; class CGovernanceObject; +class CDeterministicMNList; class uint256; // These functions dispatch to one or all registered wallets @@ -41,6 +42,7 @@ protected: virtual void NotifyGovernanceVote(const CGovernanceVote &vote) {} virtual void NotifyGovernanceObject(const CGovernanceObject &object) {} virtual void NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx) {} + virtual void NotifyMasternodeListChanged(const CDeterministicMNList& newList) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual bool UpdatedTransaction(const uint256 &hash) { return false;} virtual void Inventory(const uint256 &hash) {} @@ -80,6 +82,8 @@ struct CMainSignals { boost::signals2::signal NotifyGovernanceObject; /** Notifies listeners of a attempted InstantSend double spend*/ boost::signals2::signal NotifyInstantSendDoubleSpendAttempt; + /** Notifies listeners that the MN list changed */ + boost::signals2::signal NotifyMasternodeListChanged; /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a new active block chain. */