Remove all legacy/compatibility MN code (#2600)

* Remove CActiveLegacyMasternodeManager

* Remove sentinelping RPC

* Remove unused P2P messages and inv types

There are still places where these are used in the code. The next commits
will clean these up.

* Remove MNB/MNP/MNVERIFY related code from masternode(man).h/cpp

* Remove all legacy code regarding block MN payee voting

* Remove MASTERNODE_SYNC_LIST and MASTERNODE_SYNC_MNW states

Also replace all uses of IsMasternodeListSynced and IsWinnersListSynced
with IsBlockchainSynced.

* Remove unsupported masternode RPCs

* Remove UpdateLastPaid methods

* Remove duplicate deterministicmns.h include

* Remove masternode.conf support

* Remove legacy MN lists support from masternode list GUI

* Remove unnecessary AskForMN call

* Remove compatibility code in CPrivateSendQueue::GetSignatureHash

* Don't add locally calculated MN payee in case GetBlockTxOuts failed

This is not valid in DIP3 mode

* Remove check for IsDeterministicMNsSporkActive in "masternode status"

* Move CMasternode::IsValidNetAddr to CActiveDeterministicMasternodeManager

* Remove use of CMasternode::CheckCollateral in governance code

* Remove uses of MASTERNODE_SENTINEL_PING_MAX_SECONDS/MASTERNODE_SENTINEL_PING_MAX_SECONDS

* Remove support for "-masternodeprivkey"

* Remove pre-DIP3 vote cleanup

* Remove compatibility code for quorumModifierHash/masternodeProTxHash

* Remove check for invalid nBlockHeight in CMasternodePayments::GetBlockTxOuts

...and let it crash instead. We expect this method to be called with the
correct height now (after DIP3 was fully deployed).

* Remove ECDSA based Sign/CheckSignature from CGovernanceObject

Only masternodes sign governance objects, so there is no need for ECDSA
support here anymore.

* Always add superblock and MN reward payments into new block

* Always check block payees (except if fLiteMode==true)

* Always allow superblock and MN payees in same block

* Remove/Fix a few references to masternode.conf and related stuff

Also delete guide-startmany.md and masternode_conf.md

* Implement NotifyMasternodeListChanged signal and call governance maintenance

* Remove non-DIP3 code path from CMasternodeMan::Find

* Remove remaining unused code from CMasternode/CMasternodeMan

* Always load governance.dat on startup

* Mine an empty block instead of incrementing nHeight from chain tip in miner tests

This test is crashing otherwise in GetBlockTxOuts as it tries to access a
previous block that is not existing.

* Skip MN payments verification on historical blocks (pre-DIP3 blocks)

Even though DIP3 was active on BIP9 level, the spork was not active yet at
that point meaning that payments were not enforced at that time.

* Remove unused state and CollateralStatus enums

* Unconditionally return false from IsBlockPayeeValid when IsTransactionValid returns false

IsTransactionValid already handles the case where IsDIP3Active() returns
false, making it return true.

* Add override keyword to CDSNotificationInterface::NotifyMasternodeListChanged

* Fix help for masternodelist status (POSE_BANNED and no OUTPOINT_SPENT)
This commit is contained in:
Alexander Block 2019-01-03 10:17:43 +01:00 committed by UdjinM6
parent 46a6fc33e8
commit f95aae2b30
54 changed files with 210 additions and 7092 deletions

View File

@ -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*

View File

@ -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

View File

@ -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.
## <a name="masternodeconf"></a>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" : "<collateral_output>-<collateral_output_index>",
"service" : "<ipaddress>:<port>",
"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._

View File

@ -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

View File

@ -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 \<alias\>
* start-all
* start-missing
* start-disabled
* outputs

View File

@ -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 \

View File

@ -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());
}

View File

@ -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<CBLSPublicKey> blsPubKeyOperator;
std::unique_ptr<CBLSSecretKey> 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

View File

@ -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++)

View File

@ -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();
}

View File

@ -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;

View File

@ -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);

View File

@ -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<uint256> 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;
}

View File

@ -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<uint256> RemoveInvalidProposalVotes(const COutPoint& mnOutpoint);
void CheckOrphanVotes(CConnman& connman);
// TODO can be removed after DIP3 is fully deployed
std::vector<uint256> RemoveOldVotes(unsigned int nMinTime);
};

View File

@ -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);
}
}
}

View File

@ -457,9 +457,6 @@ private:
void RemoveInvalidProposalVotes();
// TODO can be removed after full DIP3 deployment
unsigned int GetMinVoteTime();
void ClearPreDIP3Votes();
};
#endif

View File

@ -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<CMasternodeMan> flatdb1("mncache.dat", "magicMasternodeCache");
flatdb1.Dump(mnodeman);
CFlatDB<CMasternodePayments> flatdb2("mnpayments.dat", "magicMasternodePaymentsCache");
flatdb2.Dump(mnpayments);
CFlatDB<CGovernanceManager> flatdb3("governance.dat", "magicGovernanceCache");
flatdb3.Dump(governance);
CFlatDB<CNetFulfilledRequestManager> flatdb4("netfulfilled.dat", "magicFulfilledCache");
@ -589,9 +586,6 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Masternode options:"));
strUsage += HelpMessageOpt("-masternode=<n>", strprintf(_("Enable the client to act as a masternode (0-1, default: %u)"), 0));
strUsage += HelpMessageOpt("-mnconf=<file>", strprintf(_("Specify masternode configuration file (default: %s)"), "masternode.conf"));
strUsage += HelpMessageOpt("-mnconflock=<n>", strprintf(_("Lock masternodes from masternode configuration file (default: %u)"), 1));
strUsage += HelpMessageOpt("-masternodeprivkey=<n>", _("Set the masternode private key"));
strUsage += HelpMessageOpt("-masternodeblsprivkey=<hex>", _("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<CMasternodePayments> 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<CGovernanceManager> 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<CGovernanceManager> 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);

View File

@ -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;
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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<CTxOut>& voutMasternodePaymentsRet, std::vector<CTxOut>& voutSuperblockPaymentsRet);
std::map<int, std::string> GetRequiredPaymentsStrings(int nStartHeight, int nEndHeight);
class CMasternodePayee
{
private:
CScript scriptPubKey;
std::vector<uint256> vecVoteHashes;
public:
CMasternodePayee() :
scriptPubKey(),
vecVoteHashes()
{}
CMasternodePayee(CScript payee, uint256 hashIn) :
scriptPubKey(payee),
vecVoteHashes()
{
vecVoteHashes.push_back(hashIn);
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
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<uint256> 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<CMasternodePayee> vecPayees;
CMasternodeBlockPayees() :
nBlockHeight(0),
vecPayees()
{}
CMasternodeBlockPayees(int nBlockHeightIn) :
nBlockHeight(nBlockHeightIn),
vecPayees()
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
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<unsigned char> 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 <typename Stream, typename Operation>
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<uint256, CMasternodePaymentVote> mapMasternodePaymentVotes;
std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks;
std::map<COutPoint, int> mapMasternodesLastVote;
std::map<COutPoint, int> mapMasternodesDidNotVote;
CMasternodePayments() : nStorageCoeff(1.25), nMinBlocksToStore(6000) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
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<CTxOut>& 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<CTxOut>& 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

View File

@ -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) {

View File

@ -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; }

View File

@ -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

View File

@ -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<unsigned char> 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 <typename Stream, typename Operation>
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<unsigned char> 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<uint256, int> 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<masternode_info_t&>(*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 <typename Stream, typename Operation>
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<unsigned char> vchSig1{};
std::vector<unsigned char> vchSig2{};
CMasternodeVerification() = default;
CMasternodeVerification(CService addr, int nonce, int nBlockHeight) :
addr(addr),
nonce(nonce),
nBlockHeight(nBlockHeight)
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
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

View File

@ -1,91 +0,0 @@
#include "netbase.h"
#include "masternodeconfig.h"
#include "util.h"
#include "chainparams.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
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;
}

View File

@ -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<CMasternodeEntry>();
}
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<CMasternodeEntry>& getEntries() {
return entries;
}
int getCount() {
return (int)entries.size();
}
private:
std::vector<CMasternodeEntry> entries;
};
#endif /* SRC_MASTERNODECONFIG_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -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<COutPoint, CMasternode> mapMasternodes;
// who's asked for the Masternode list and the last time
std::map<CService, int64_t> mAskedUsForMasternodeList;
// who we asked for the Masternode list and the last time
std::map<CService, int64_t> mWeAskedForMasternodeList;
// which Masternodes we've asked for
std::map<COutPoint, std::map<CService, int64_t> > mWeAskedForMasternodeListEntry;
// who we asked for the masternode verification
std::map<CService, CMasternodeVerification> mWeAskedForVerification;
// these maps are used for masternode recovery from MASTERNODE_NEW_START_REQUIRED state
std::map<uint256, std::pair< int64_t, std::set<CService> > > mMnbRecoveryRequests;
std::map<uint256, std::vector<CMasternodeBroadcast> > mMnbRecoveryGoodReplies;
std::list< std::pair<CService, uint256> > listScheduledMnbRequestConnections;
std::map<CService, std::pair<int64_t, std::set<uint256> > > mapPendingMNB;
std::map<CService, std::pair<int64_t, CMasternodeVerification> > 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<uint256> 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<uint256, std::pair<int64_t, CMasternodeBroadcast> > mapSeenMasternodeBroadcast;
// Keep track of all pings I've seen
std::map<uint256, CMasternodePing> mapSeenMasternodePing;
// Keep track of all verifications I've seen
std::map<uint256, CMasternodeVerification> 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<COutPoint, CMasternode> 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<CService, std::set<uint256> > 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);
};

View File

@ -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<bool>(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<uint256> 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<int> legacyMNObjs = {
MSG_MASTERNODE_PAYMENT_VOTE,
MSG_MASTERNODE_PAYMENT_BLOCK,
MSG_MASTERNODE_ANNOUNCE,
MSG_MASTERNODE_PING,
MSG_MASTERNODE_VERIFY,
};
static std::set<int> 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);

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -49,295 +49,12 @@
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabMyMasternodes">
<attribute name="title">
<string>My Masternodes</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_note">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="updateNote">
<property name="text">
<string>Note: Status of your masternodes in local wallet can potentially be slightly incorrect.&lt;br /&gt;Always wait for wallet to sync additional data and then double check from another node&lt;br /&gt;if your masternode should be running but you still do not see &quot;ENABLED&quot; in &quot;Status&quot; field.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tableWidgetMyMasternodes">
<property name="minimumSize">
<size>
<width>695</width>
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Alias</string>
</property>
</column>
<column>
<property name="text">
<string>Address</string>
</property>
</column>
<column>
<property name="text">
<string>Protocol</string>
</property>
</column>
<column>
<property name="text">
<string>Status</string>
</property>
</column>
<column>
<property name="text">
<string>Active</string>
</property>
</column>
<column>
<property name="text">
<string>Last Seen</string>
</property>
</column>
<column>
<property name="text">
<string>Payee</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="startButton">
<property name="text">
<string>S&amp;tart alias</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="startAllButton">
<property name="text">
<string>Start &amp;all</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="startMissingButton">
<property name="text">
<string>Start &amp;MISSING</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="UpdateButton">
<property name="text">
<string>&amp;Update status</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="QRButton">
<property name="toolTip">
<string>Show additional Masternode information</string>
</property>
<property name="text">
<string>Show &amp;Info...</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="autoupdate_label">
<property name="text">
<string>Status will be updated automatically in (sec):</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="secondsLabel">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabAllMasternodes">
<attribute name="title">
<string>All Masternodes</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" rowspan="2" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_filter">
<property name="text">
<string>Filter List:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="filterLineEdit">
<property name="toolTip">
<string>Filter masternode list</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_count">
<property name="text">
<string>Node Count:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="countLabel">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QTableWidget" name="tableWidgetMasternodes">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Address</string>
</property>
</column>
<column>
<property name="text">
<string>Protocol</string>
</property>
</column>
<column>
<property name="text">
<string>Status</string>
</property>
</column>
<column>
<property name="text">
<string>Active</string>
</property>
</column>
<column>
<property name="text">
<string>Last Seen</string>
</property>
</column>
<column>
<property name="text">
<string>Payee</string>
</property>
</column>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="legacyListNote">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabDIP3Masternodes">
<attribute name="title">
<string>DIP3 Masternodes</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="bottomMargin">
<number>0</number>
@ -385,7 +102,7 @@
</item>
</layout>
</item>
<item row="2" column="0">
<item row="1" column="0">
<widget class="QTableWidget" name="tableWidgetMasternodesDIP3">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
@ -447,19 +164,6 @@
</column>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="dip3NoteLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@ -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();

View File

@ -117,9 +117,6 @@ namespace GUIUtil
// Open dash.conf
void openConfigfile();
// Open masternode.conf
void openMNConfigfile();
// Browse backup folder
void showBackups();

View File

@ -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 += "<center>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 += "<br>Successfully started masternode.";
mnodeman.NotifyMasternodeUpdates(*g_connman);
} else {
strStatusHtml += "<br>Failed to start masternode.<br>Error: " + strError;
}
break;
}
}
strStatusHtml += "</center>";
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<COutPoint, CMasternode> 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 = "<html><font face='verdana, arial, helvetica, sans-serif'>";
strHTML += "<b>" + tr("Alias") + ": </b>" + GUIUtil::HtmlEscape(strAlias) + "<br>";
strHTML += "<b>" + tr("Private Key") + ": </b>" + GUIUtil::HtmlEscape(strMNPrivKey) + "<br>";
strHTML += "<b>" + tr("Collateral") + ": </b>" + GUIUtil::HtmlEscape(strCollateral) + "<br>";
strHTML += "<b>" + tr("IP") + ": </b>" + GUIUtil::HtmlEscape(strIP) + "<br>";
if (fFound) {
strHTML += "<b>" + tr("Protocol") + ": </b>" + QString::number(mn.nProtocolVersion) + "<br>";
strHTML += "<b>" + tr("Version") + ": </b>" + (mn.lastPing.nDaemonVersion > DEFAULT_DAEMON_VERSION ? GUIUtil::HtmlEscape(FormatVersion(mn.lastPing.nDaemonVersion)) : tr("Unknown")) + "<br>";
strHTML += "<b>" + tr("Sentinel") + ": </b>" + (mn.lastPing.nSentinelVersion > DEFAULT_SENTINEL_VERSION ? GUIUtil::HtmlEscape(SafeIntVersionToString(mn.lastPing.nSentinelVersion)) : tr("Unknown")) + "<br>";
strHTML += "<b>" + tr("Status") + ": </b>" + GUIUtil::HtmlEscape(CMasternode::StateToString(mn.nActiveState)) + "<br>";
strHTML += "<b>" + tr("Payee") + ": </b>" + GUIUtil::HtmlEscape(CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString()) + "<br>";
strHTML += "<b>" + tr("Active") + ": </b>" + GUIUtil::HtmlEscape(DurationToDHMS(mn.lastPing.sigTime - mn.sigTime)) + "<br>";
strHTML += "<b>" + tr("Last Seen") + ": </b>" + GUIUtil::HtmlEscape(DateTimeStrFormat("%Y-%m-%d %H:%M", mn.lastPing.sigTime + GetOffsetFromUtc())) + "<br>";
}
// 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;

View File

@ -12,7 +12,6 @@
#include <QTimer>
#include <QWidget>
#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();

View File

@ -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);

View File

@ -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"

View File

@ -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));

View File

@ -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 <fstream>
#include <iomanip>
#include <univalue.h>
@ -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<CMasternodeConfig::CMasternodeEntry>& 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<CMasternodeConfig::CMasternodeEntry> 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<CMasternodeConfig::CMasternodeEntry> 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-<mode> - Start remote masternodes configured in masternode.conf (<mode>: '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<CMasternodeBroadcast>& vecMnb, std::string strHexMnb) {
if (!IsHex(strHexMnb))
return false;
std::vector<unsigned char> 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<CMasternodeBroadcast> 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<CMasternodeBroadcast> 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<CMasternodeBroadcast> 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<CMasternodeBroadcast> 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

View File

@ -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<CTxOut> 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...");

View File

@ -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;

View File

@ -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<CBlockTemplate> pblocktemplate;
std::unique_ptr<CBlockTemplate> 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<CTransactionRef> 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<const CBlock> shared_pblock = std::make_shared<const CBlock>(*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();

View File

@ -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()

View File

@ -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));

View File

@ -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);

View File

@ -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();
}

View File

@ -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 &currentTx, 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<void (const CGovernanceObject &)> NotifyGovernanceObject;
/** Notifies listeners of a attempted InstantSend double spend*/
boost::signals2::signal<void(const CTransaction &currentTx, const CTransaction &previousTx)> NotifyInstantSendDoubleSpendAttempt;
/** Notifies listeners that the MN list changed */
boost::signals2::signal<void(const CDeterministicMNList& newList)> NotifyMasternodeListChanged;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<bool (const uint256 &)> UpdatedTransaction;
/** Notifies listeners of a new active block chain. */