From 4286dde4989832c0f03acc130a4f6a669fb5fdda Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2019 17:17:30 +0200 Subject: [PATCH 01/19] Remove support for InstantSend locked gobject collaterals (#3019) --- src/governance-object.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/governance-object.cpp b/src/governance-object.cpp index 4dec7fda6fd4c..978cee82c4fad 100644 --- a/src/governance-object.cpp +++ b/src/governance-object.cpp @@ -8,7 +8,6 @@ #include "governance-validators.h" #include "governance-vote.h" #include "governance.h" -#include "instantx.h" #include "masternode-meta.h" #include "masternode-sync.h" #include "messagesigner.h" @@ -16,8 +15,6 @@ #include "util.h" #include "validation.h" -#include "llmq/quorums_instantsend.h" - #include #include @@ -599,8 +596,7 @@ bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingC } } - if ((nConfirmationsIn < GOVERNANCE_FEE_CONFIRMATIONS) && - (!instantsend.IsLockedInstantSendTransaction(nCollateralHash) || llmq::quorumInstantSendManager->IsLocked(nCollateralHash))) { + if ((nConfirmationsIn < GOVERNANCE_FEE_CONFIRMATIONS)) { strError = strprintf("Collateral requires at least %d confirmations to be relayed throughout the network (it has only %d)", GOVERNANCE_FEE_CONFIRMATIONS, nConfirmationsIn); if (nConfirmationsIn >= GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS) { fMissingConfirmations = true; From ea8569e97b3b33485bd67b8b69f509548294b402 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Mon, 15 Jul 2019 14:38:55 +0300 Subject: [PATCH 02/19] Backport #12783: macOS: disable AppNap during sync (and mixing) (#3024) * Merge #12783: macOS: disable AppNap during sync 1e0f3c44992fb82e6bf36c2ef9277b0759c17c4c macOS: disable AppNap during sync (Alexey Ivanov) Pull request description: Code based on pull/5804. Tested only on macOS 10.13.3 and should support 10.9+. What macOS versions bitcoin core currently supports? Tree-SHA512: 85809b8d8d8a05169437b4268988da0b7372c29c6da3223ebdc106dc16dcb6d3caa5c52ace3591467005b50a63fd8b2ab1cb071cb4f450032932df25d5063315 * Refactor * Drop `#include ` from `src/qt/bitcoingui.h` Was included by mistake. --- share/qt/Info.plist.in | 3 -- src/Makefile.qt.include | 4 ++- src/qt/bitcoingui.cpp | 19 +++++++++++ src/qt/bitcoingui.h | 8 +++++ src/qt/macos_appnap.h | 24 ++++++++++++++ src/qt/macos_appnap.mm | 71 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 src/qt/macos_appnap.h create mode 100644 src/qt/macos_appnap.mm diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index 41f37eb43cb9b..ff1f26cdd959d 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -97,9 +97,6 @@ NSHighResolutionCapable True - LSAppNapIsDisabled - True - NSRequiresAquaSystemAppearance True diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index a50bf431334eb..6ce8af69ba5e4 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -102,7 +102,8 @@ QT_MOC_CPP = \ BITCOIN_MM = \ qt/macdockiconhandler.mm \ - qt/macnotificationhandler.mm + qt/macnotificationhandler.mm \ + qt/macos_appnap.mm QT_MOC = \ qt/dash.moc \ @@ -139,6 +140,7 @@ BITCOIN_QT_H = \ qt/intro.h \ qt/macdockiconhandler.h \ qt/macnotificationhandler.h \ + qt/macos_appnap.h \ qt/modaloverlay.h \ qt/masternodelist.h \ qt/networkstyle.h \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 065ebf2e73622..9ca1bd27157df 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -24,6 +24,7 @@ #include "utilitydialog.h" #ifdef ENABLE_WALLET +#include "privatesend-client.h" #include "walletframe.h" #include "walletmodel.h" #endif // ENABLE_WALLET @@ -266,6 +267,10 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * connect(progressBar, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay())); } #endif + +#ifdef Q_OS_MAC + m_app_nap_inhibitor = new CAppNapInhibitor; +#endif } BitcoinGUI::~BitcoinGUI() @@ -277,6 +282,7 @@ BitcoinGUI::~BitcoinGUI() if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) trayIcon->hide(); #ifdef Q_OS_MAC + delete m_app_nap_inhibitor; delete appMenuBar; MacDockIconHandler::cleanup(); #endif @@ -950,6 +956,19 @@ void BitcoinGUI::updateHeadersSyncProgressLabel() void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header) { +#ifdef Q_OS_MAC + // Disabling macOS App Nap on initial sync, disk, reindex operations and mixing. + bool disableAppNap = !masternodeSync.IsSynced(); +#ifdef ENABLE_WALLET + disableAppNap |= privateSendClient.fPrivateSendRunning; +#endif // ENABLE_WALLET + if (disableAppNap) { + m_app_nap_inhibitor->disableAppNap(); + } else { + m_app_nap_inhibitor->enableAppNap(); + } +#endif // Q_OS_MAC + if (modalOverlay) { if (header) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index e01da23c4e838..6d120a90387a0 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -19,6 +19,10 @@ #include #include +#ifdef Q_OS_MAC +#include +#endif + class ClientModel; class NetworkStyle; class Notificator; @@ -133,6 +137,10 @@ class BitcoinGUI : public QMainWindow HelpMessageDialog *helpMessageDialog; ModalOverlay *modalOverlay; +#ifdef Q_OS_MAC + CAppNapInhibitor* m_app_nap_inhibitor = nullptr; +#endif + /** Keep track of previous number of blocks, to detect progress */ int prevBlocks; int spinnerFrame; diff --git a/src/qt/macos_appnap.h b/src/qt/macos_appnap.h new file mode 100644 index 0000000000000..8c2cd840b01c8 --- /dev/null +++ b/src/qt/macos_appnap.h @@ -0,0 +1,24 @@ +// Copyright (c) 2011-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_MACOS_APPNAP_H +#define BITCOIN_QT_MACOS_APPNAP_H + +#include + +class CAppNapInhibitor final +{ +public: + explicit CAppNapInhibitor(); + ~CAppNapInhibitor(); + + void disableAppNap(); + void enableAppNap(); + +private: + class CAppNapImpl; + std::unique_ptr impl; +}; + +#endif // BITCOIN_QT_MACOS_APPNAP_H diff --git a/src/qt/macos_appnap.mm b/src/qt/macos_appnap.mm new file mode 100644 index 0000000000000..363c60091fb63 --- /dev/null +++ b/src/qt/macos_appnap.mm @@ -0,0 +1,71 @@ +// Copyright (c) 2011-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "macos_appnap.h" + +#include +#include +#include + +class CAppNapInhibitor::CAppNapImpl +{ +public: + ~CAppNapImpl() + { + if(activityId) + enableAppNap(); + } + + void disableAppNap() + { + if (!activityId) + { + @autoreleasepool { + const NSActivityOptions activityOptions = + NSActivityUserInitiatedAllowingIdleSystemSleep & + ~(NSActivitySuddenTerminationDisabled | + NSActivityAutomaticTerminationDisabled); + + id processInfo = [NSProcessInfo processInfo]; + if ([processInfo respondsToSelector:@selector(beginActivityWithOptions:reason:)]) + { + activityId = [processInfo beginActivityWithOptions: activityOptions reason:@"Temporarily disable App Nap for dash-qt."]; + [activityId retain]; + } + } + } + } + + void enableAppNap() + { + if(activityId) + { + @autoreleasepool { + id processInfo = [NSProcessInfo processInfo]; + if ([processInfo respondsToSelector:@selector(endActivity:)]) + [processInfo endActivity:activityId]; + + [activityId release]; + activityId = nil; + } + } + } + +private: + NSObject* activityId; +}; + +CAppNapInhibitor::CAppNapInhibitor() : impl(new CAppNapImpl()) {} + +CAppNapInhibitor::~CAppNapInhibitor() = default; + +void CAppNapInhibitor::disableAppNap() +{ + impl->disableAppNap(); +} + +void CAppNapInhibitor::enableAppNap() +{ + impl->enableAppNap(); +} From 873ab896ca92f1e56d182338fb863e3d0ec87f4b Mon Sep 17 00:00:00 2001 From: Nathan Marley Date: Mon, 15 Jul 2019 08:39:14 -0300 Subject: [PATCH 03/19] Fix osslsigncode compile issue in gitian-build (#3026) --- contrib/gitian-descriptors/gitian-win-signer.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index feb94ff920c83..31225426a7ef2 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -5,7 +5,8 @@ suites: architectures: - "amd64" packages: -- "libssl-dev" +# Once osslsigncode supports openssl 1.1, we can change this back to libssl-dev +- "libssl1.0-dev" - "autoconf" remotes: - "url": "https://github.com/dashpay/dash-detached-sigs.git" From 5af6ce91d6add1e85778438ee76a93c027704cd5 Mon Sep 17 00:00:00 2001 From: Nathan Marley Date: Tue, 16 Jul 2019 06:38:17 -0300 Subject: [PATCH 04/19] Add Dash Core Group codesign certificate (#3027) --- contrib/windeploy/win-codesign.cert | 169 +++++++++++++--------------- 1 file changed, 76 insertions(+), 93 deletions(-) diff --git a/contrib/windeploy/win-codesign.cert b/contrib/windeploy/win-codesign.cert index 200b30a3f0d2f..df99179ba74c2 100644 --- a/contrib/windeploy/win-codesign.cert +++ b/contrib/windeploy/win-codesign.cert @@ -1,99 +1,82 @@ -----BEGIN CERTIFICATE----- -MIIFTTCCBDWgAwIBAgIRALlW05RLwG2hMQMX5d/o5J8wDQYJKoZIhvcNAQELBQAw -fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxIzAhBgNV -BAMTGkNPTU9ETyBSU0EgQ29kZSBTaWduaW5nIENBMB4XDTE2MDIwMzAwMDAwMFoX -DTE5MDMwNTIzNTk1OVowgbUxCzAJBgNVBAYTAlVTMQ4wDAYDVQQRDAU5ODEwNDEL -MAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAkMB1N0ZSAzMDAx -FzAVBgNVBAkMDjcxIENvbHVtYmlhIFN0MSUwIwYDVQQKDBxUaGUgQml0Y29pbiBG -b3VuZGF0aW9uLCBJbmMuMSUwIwYDVQQDDBxUaGUgQml0Y29pbiBGb3VuZGF0aW9u -LCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw37Vrv9Gbku0 -+kuV0t89TuyxtAcmT7QE4GcwESKKjmkxfzD9a0qlhqk8GfQ+fw4DHNN+nLKNv7xB -bk6aS7J2v2DcXkOjrP99P9jqgTkp7MC04VtG3OqVRGB+gum0pptRovYZUQXIdkY7 -GJOok/NDagwKiiUe2V2meZ7UctsZNvYeilQdTgKIIhrMB9NowCOhT8ocVL4Ki55/ -l7hukJn3fueCM3fHTwY2/1gaGsOHoCkFRsD7vokjAVpiY+8rUgvHjb0gxgojiVGd -6a6/F5XJwKJacvUyN4Hfc2K5lRMQjTTmo4aWNWIa0iJ3TK9BHpdSLJBqerMPvmnM -kkapS+ZTNQIDAQABo4IBjTCCAYkwHwYDVR0jBBgwFoAUKZFg/4pN+uv5pmq4z/nm -S71JzhIwHQYDVR0OBBYEFONpQ+cV82URVe+V8G57377KxxexMA4GA1UdDwEB/wQE -AwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG -+EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDAjArMCkGCCsGAQUF -BwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBDBgNVHR8EPDA6MDig -NqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDb2RlU2lnbmlu -Z0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQu -Y29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWduaW5nQ0EuY3J0MCQGCCsGAQUF -BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB -AGnBSi9K/9rgTAyKFKrfGWSfNOwAghmsnsvpZSQ7QyoGWBFKSgCs/70kErl18oHA -g7Y8loQB1yukZmJaCa3OvGud7smn45TCh0TMf4EpP20Wxf4rMQTxwAatasHL3+vi -I+Nl5bsRZ09kWjvayqLII5upjS/yq0JfpmyGl5k2C/fIpztq0iOLvqWlXcL4+51r -cMUAfX6E6EaZQm//ikp+w2+7MEXTKguOuV3gwsrTy0DsvkZl4YDgx/FA4ImzXopv -d+3KJPLvO+OSBqUD3JPwXHnuJqGAbLBFyyCa/feGUjLlR8cxcNWLWdp4qxtoIUPG -3wTsC9YgrglS0F7FKMXlNRY= +MIIFNzCCBB+gAwIBAgIQC/8xYSjtiyFcuq4bKws+RTANBgkqhkiG9w0BAQsFADBy +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQg +SUQgQ29kZSBTaWduaW5nIENBMB4XDTE5MDcxMTAwMDAwMFoXDTIwMDcxNTEyMDAw +MFowdDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj +b3R0c2RhbGUxHjAcBgNVBAoTFURhc2ggQ29yZSBHcm91cCwgSW5jLjEeMBwGA1UE +AxMVRGFzaCBDb3JlIEdyb3VwLCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsMVXODC4TqTzNRALu+Kqz57dyv1wSTWBQ4XOJlAhh0ovbKhiL9BQ +hHeYtbhlPaeMiy/zRsAU/SNBwcpKfc5MkTurh3UxGg44VV/uQk2vm0x2lu3fhye9 +R87SvLk57FKcxrQI0tWrSs9xN/el+Bb2sw04Xy7PvTYJ9fnDJQ/Fg4qfC/4F8c/+ +w17/WHAA/7zOSjwzF52LQjjDEGwtb6P8xSSdNSon2MVSP8Qxts+x0ovIsQyLTQxf +OiRBsz5VIXi9xahB/qF51dGGT9GSTrwozpiEiNEUD9R8R8EBbNyZhB0y5UD4+gJn +sD2nf8U5l6PPFmN1RmOQ9s4Qa/8TwgA4QwIDAQABo4IBxTCCAcEwHwYDVR0jBBgw +FoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFCVaMjaUGDJeJ9P13zgU +OYhlWt9zMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNV +HR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1 +cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3No +YTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAo +BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwB +BAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln +aWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j +b20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0T +AQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAabFJzX4GGQySz89L1+snLTsBXUZ5 +hT4HrbEzcjIMxlIBi14dze9A5L7IHBi6iu4tsRpos18nCCz6ljrrYgQJhpqoMNDu +BZDJLnMAJQvtGWSR+2VCg18doAOB2LA696aFDvGq2fjuvvm0uf1bT1mrFxtn0e5s +9as1h5gk8wDP8T98LjBEp6r5cogBQrf4sc9Nl7iNN3rMAOConnrrX/zxUN8p08kP +FQ1qx8giYrQ0huXsx+YFCuTHEDw7HTgpVMCvywOZ8P8PXD8UEyibMaXxB44jhk27 +uHxhGny93NXwTYj6naNn02HSQuJaH64CfIiQDmWFjduhrPVjy3sogtk2lw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIF4DCCA8igAwIBAgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5 -MDAwMDAwWhcNMjgwNTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD -T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p -bmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR -3elnMRHrzB79MR2zuWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvth -e4YJs+P9omidHCydv3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3 -e9V5kAoUGFEs5v7BEvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQ -c5hc9IVKaw+A3V7Wvf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPi -XzjbxghdR7ODQfAuADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmL -Agaff9ULAgMBAAGjggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs -2TIy1DAdBgNVHQ4EFgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQD -AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYD -VR0gBAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29t -b2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEG -CCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5j -b20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v -Y3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4M -bU2x8U6ST6/COCwEzMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQci -GlEcOtTh6Qm/5iR0rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHf -WGshqknUfDdOvf+2dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HI -TfK7ZU2o94VFB696aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46 -BLqioXwfy2M6FafUFRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gb -qjSm/Iz13X9ljIwxVzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm -5LLY5TjCqO3GgZw1a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQ -Fhv/K53b0CDKieoofjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5s -L6iPDAZQ+4wns3bJ9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55 -ZmjoIs2475iFTZYRPAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6 -Q++6Z2H/fUnguzB9XIDj5hY5S6c= +MIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAwWjByMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBT +aWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+NOzHH8O +Ea9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6kkPApfmJ1DcZ17aq +8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQjZhJUM1B0sSgmuyRp +wsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5wMWYzcT6scKKrzn/p +fMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp6moKq4TzrGdOtcT3 +jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH5DiLanMg0A9kczye +n6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNV +HQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYIKwYBBQUHAQEEbTBr +MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUH +MAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ +RFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2lj +ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6 +Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww +TwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v +d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYEFFrEuXsq +CqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgP +MA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2qB1dHC06GsTvMGHX +fgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4QpO4/cY5jDhNLrddf +RHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEpKBo6cSgCPC6Ro8Al +EeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/DmZAwlCEIysjaKJAL+ +L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9CBoYs4GbT8aTEAb8 +B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- From 781b165796dc6d7766cf1dc99b6db8943bb5b706 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Mon, 15 Jul 2019 14:39:43 +0300 Subject: [PATCH 05/19] Merge pull request #3028 from PastaPastaPasta/backport-12588 Backport a couple of ZMQ fixes --- contrib/zmq/zmq_sub.py | 4 ++-- contrib/zmq/zmq_sub3.4.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) mode change 100755 => 100644 contrib/zmq/zmq_sub.py mode change 100755 => 100644 contrib/zmq/zmq_sub3.4.py diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py old mode 100755 new mode 100644 index 85b9a730dfbb7..a45b00d76dbde --- a/contrib/zmq/zmq_sub.py +++ b/contrib/zmq/zmq_sub.py @@ -8,8 +8,8 @@ Dash should be started with the command line arguments: dashd-testnet -daemon \ - -zmqpubhashblock=tcp://127.0.0.1:28332 \ -zmqpubrawtx=tcp://127.0.0.1:28332 \ + -zmqpubrawblock=tcp://127.0.0.1:28332 \ -zmqpubhashtx=tcp://127.0.0.1:28332 \ -zmqpubhashblock=tcp://127.0.0.1:28332 @@ -38,7 +38,7 @@ class ZMQHandler(): def __init__(self): - self.loop = zmq.asyncio.install() + self.loop = asyncio.get_event_loop() self.zmqContext = zmq.asyncio.Context() self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py old mode 100755 new mode 100644 index f84bb6fcd0f43..2987be1e7c0ee --- a/contrib/zmq/zmq_sub3.4.py +++ b/contrib/zmq/zmq_sub3.4.py @@ -8,8 +8,8 @@ Dash should be started with the command line arguments: dashd -testnet -daemon \ - -zmqpubhashblock=tcp://127.0.0.1:28332 \ -zmqpubrawtx=tcp://127.0.0.1:28332 \ + -zmqpubrawblock=tcp://127.0.0.1:28332 \ -zmqpubhashtx=tcp://127.0.0.1:28332 \ -zmqpubhashblock=tcp://127.0.0.1:28332 @@ -42,7 +42,7 @@ class ZMQHandler(): def __init__(self): - self.loop = zmq.asyncio.install() + self.loop = asyncio.get_event_loop() self.zmqContext = zmq.asyncio.Context() self.zmqSubSocket = self.zmqContext.socket(zmq.SUB) From 974055a9b6fef4c9a71b0ccc629e172cee1b5088 Mon Sep 17 00:00:00 2001 From: strophy <32928115+strophy@users.noreply.github.com> Date: Tue, 23 Jul 2019 01:06:04 +0800 Subject: [PATCH 06/19] Fix broken link in PrivateSend info dialog (#3031) --- src/qt/utilitydialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index e5bb8869e951b..0a04082385682 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -161,7 +161,7 @@ your funds will already be anonymized. No additional waiting is required. \ This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. \ It can only do this, however, if you have automatic backups enabled.
\ Consequently, users who have backups disabled will also have PrivateSend disabled.
\ -For more information, see the PrivateSend documentation." +For more information, see the PrivateSend documentation." )); ui->aboutMessage->setWordWrap(true); ui->helpMessage->setVisible(false); From b1ffedb2ddc2e0e9be04f134333dd5e7c64ca61f Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 1 Aug 2019 17:50:23 +0300 Subject: [PATCH 07/19] Do not count 0-fee txes for fee estimation (#3037) --- src/validation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 6422ac2e07b14..18baae56cb821 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -883,8 +883,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // This transaction should only count for fee estimation if the // node is not behind, and the transaction is not dependent on any other - // transactions in the mempool. - bool validForFeeEstimation = IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); + // transactions in the mempool. Also ignore 0-fee txes. + bool validForFeeEstimation = (nFees != 0) && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); // Store transaction in memory pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation); From 7ea319fd2544adac8fc07724fda1e71a06bde4c5 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Wed, 7 Aug 2019 12:55:07 +0300 Subject: [PATCH 08/19] Bail out properly on Evo DB consistency check failures in ConnectBlock/DisconnectBlock (#3044) --- src/validation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 18baae56cb821..cf8a3211a8539 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1612,6 +1612,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s if (fDIP0003Active && !fHasBestBlock) { // Nodes that upgraded after DIP3 activation will have to reindex to ensure evodb consistency AbortNode("Found EvoDB inconsistency, you must reindex to continue"); + return DISCONNECT_FAILED; } bool fClean = true; @@ -1911,7 +1912,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (fDIP0003Active && !fHasBestBlock) { // Nodes that upgraded after DIP3 activation will have to reindex to ensure evodb consistency - AbortNode("Found EvoDB inconsistency, you must reindex to continue"); + return AbortNode(state, "Found EvoDB inconsistency, you must reindex to continue"); } } From 99824a87929328ab21ec6ec5e59f608baef8b85d Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 27 Jun 2019 22:25:59 +0200 Subject: [PATCH 09/19] Implement "quorum memberof" (#3004) * Implement BuildQuorumInfo and call it from quorum_info * Add type to result of BuildQuorumInfo * Implement "quorum memberof" --- src/rpc/rpcquorums.cpp | 121 +++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index 66218aab0215a..4cfd5caf24a8a 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -76,6 +76,41 @@ void quorum_info_help() ); } +UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMembers, bool includeSkShare) +{ + UniValue ret(UniValue::VOBJ); + + ret.push_back(Pair("height", quorum->height)); + ret.push_back(Pair("type", quorum->params.name)); + ret.push_back(Pair("quorumHash", quorum->qc.quorumHash.ToString())); + ret.push_back(Pair("minedBlock", quorum->minedBlockHash.ToString())); + + if (includeMembers) { + UniValue membersArr(UniValue::VARR); + for (size_t i = 0; i < quorum->members.size(); i++) { + auto& dmn = quorum->members[i]; + UniValue mo(UniValue::VOBJ); + mo.push_back(Pair("proTxHash", dmn->proTxHash.ToString())); + mo.push_back(Pair("valid", quorum->qc.validMembers[i])); + if (quorum->qc.validMembers[i]) { + CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); + if (pubKey.IsValid()) { + mo.push_back(Pair("pubKeyShare", pubKey.ToString())); + } + } + membersArr.push_back(mo); + } + + ret.push_back(Pair("members", membersArr)); + } + ret.push_back(Pair("quorumPublicKey", quorum->qc.quorumPublicKey.ToString())); + CBLSSecretKey skShare = quorum->GetSkShare(); + if (includeSkShare && skShare.IsValid()) { + ret.push_back(Pair("secretKeyShare", skShare.ToString())); + } + return ret; +} + UniValue quorum_info(const JSONRPCRequest& request) { if (request.fHelp || (request.params.size() != 3 && request.params.size() != 4)) @@ -101,35 +136,7 @@ UniValue quorum_info(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found"); } - UniValue ret(UniValue::VOBJ); - - ret.push_back(Pair("height", quorum->height)); - ret.push_back(Pair("quorumHash", quorum->qc.quorumHash.ToString())); - ret.push_back(Pair("minedBlock", quorum->minedBlockHash.ToString())); - - UniValue membersArr(UniValue::VARR); - for (size_t i = 0; i < quorum->members.size(); i++) { - auto& dmn = quorum->members[i]; - UniValue mo(UniValue::VOBJ); - mo.push_back(Pair("proTxHash", dmn->proTxHash.ToString())); - mo.push_back(Pair("valid", quorum->qc.validMembers[i])); - if (quorum->qc.validMembers[i]) { - CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); - if (pubKey.IsValid()) { - mo.push_back(Pair("pubKeyShare", pubKey.ToString())); - } - } - membersArr.push_back(mo); - } - - ret.push_back(Pair("members", membersArr)); - ret.push_back(Pair("quorumPublicKey", quorum->qc.quorumPublicKey.ToString())); - CBLSSecretKey skShare = quorum->GetSkShare(); - if (includeSkShare && skShare.IsValid()) { - ret.push_back(Pair("secretKeyShare", skShare.ToString())); - } - - return ret; + return BuildQuorumInfo(quorum, true, includeSkShare); } void quorum_dkgstatus_help() @@ -182,6 +189,59 @@ UniValue quorum_dkgstatus(const JSONRPCRequest& request) return ret; } +void quorum_memberof_help() +{ + throw std::runtime_error( + "quorum memberof \"proTxHash\"\n" + "Checks which quorums the given masternode is a member of.\n" + "\nArguments:\n" + "1. \"proTxHash\" (string, required) ProTxHash of the masternode.\n" + ); +} + +UniValue quorum_memberof(const JSONRPCRequest& request) +{ + if (request.fHelp || (request.params.size() != 2)) { + quorum_memberof_help(); + } + + uint256 protxHash = ParseHashV(request.params[1], "proTxHash"); + + const CBlockIndex* pindexTip; + { + LOCK(cs_main); + pindexTip = chainActive.Tip(); + } + + auto mnList = deterministicMNManager->GetListForBlock(pindexTip->GetBlockHash()); + auto dmn = mnList.GetMN(protxHash); + if (!dmn) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "masternode not found"); + } + + std::set> quorumHashes; + for (const auto& p : Params().GetConsensus().llmqs) { + auto& params = p.second; + auto quorums = llmq::quorumManager->ScanQuorums(params.type, params.signingActiveQuorumCount); + for (auto& quorum : quorums) { + for (auto& m : quorum->members) { + if (m->proTxHash == dmn->proTxHash) { + quorumHashes.emplace(params.type, quorum->qc.quorumHash); + } + } + } + } + + UniValue result(UniValue::VARR); + for (auto& p : quorumHashes) { + auto quorum = llmq::quorumManager->GetQuorum(p.first, p.second); + assert(quorum); + result.push_back(BuildQuorumInfo(quorum, false, false)); + } + + return result; +} + void quorum_sign_help() { throw std::runtime_error( @@ -318,6 +378,7 @@ UniValue quorum_dkgsimerror(const JSONRPCRequest& request) " info - Return information about a quorum\n" " dkgsimerror - Simulates DKG errors and malicious behavior.\n" " dkgstatus - Return the status of the current DKG process\n" + " memberof - Checks which quorums the given masternode is a member of\n" " sign - Threshold-sign a message\n" " hasrecsig - Test if a valid recovered signature is present\n" " getrecsig - Get a recovered signature\n" @@ -342,6 +403,8 @@ UniValue quorum(const JSONRPCRequest& request) return quorum_info(request); } else if (command == "dkgstatus") { return quorum_dkgstatus(request); + } else if (command == "memberof") { + return quorum_memberof(request); } else if (command == "sign" || command == "hasrecsig" || command == "getrecsig" || command == "isconflicting") { return quorum_sigs_cmd(request); } else if (command == "dkgsimerror") { From 9ac7a998be7e0399078cd6c82aea7767b8080395 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 2 Jul 2019 22:44:29 +0200 Subject: [PATCH 10/19] Add "isValidMember" and "memberIndex" to "quorum memberof" and allow to specify quorum scan count (#3009) * Add "isValidMember" and "memberIndex" to output of "quorum memberof" * Allow to specify how many quorums to scan for in "quorum memberof" --- src/rpc/rpcquorums.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index 4cfd5caf24a8a..b9709ef8c9020 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -192,20 +192,29 @@ UniValue quorum_dkgstatus(const JSONRPCRequest& request) void quorum_memberof_help() { throw std::runtime_error( - "quorum memberof \"proTxHash\"\n" + "quorum memberof \"proTxHash\" (quorumCount)\n" "Checks which quorums the given masternode is a member of.\n" "\nArguments:\n" "1. \"proTxHash\" (string, required) ProTxHash of the masternode.\n" + "2. scanQuorumsCount (number, optional) Number of quorums to scan for. If not specified,\n" + " the active quorum count for each specific quorum type is used." ); } UniValue quorum_memberof(const JSONRPCRequest& request) { - if (request.fHelp || (request.params.size() != 2)) { + if (request.fHelp || (request.params.size() < 2 || request.params.size() > 3)) { quorum_memberof_help(); } uint256 protxHash = ParseHashV(request.params[1], "proTxHash"); + int scanQuorumsCount = -1; + if (request.params.size() >= 3) { + scanQuorumsCount = ParseInt32V(request.params[2], "scanQuorumsCount"); + if (scanQuorumsCount <= 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid scanQuorumsCount parameter"); + } + } const CBlockIndex* pindexTip; { @@ -219,26 +228,25 @@ UniValue quorum_memberof(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "masternode not found"); } - std::set> quorumHashes; + UniValue result(UniValue::VARR); + for (const auto& p : Params().GetConsensus().llmqs) { auto& params = p.second; - auto quorums = llmq::quorumManager->ScanQuorums(params.type, params.signingActiveQuorumCount); + size_t count = params.signingActiveQuorumCount; + if (scanQuorumsCount != -1) { + count = (size_t)scanQuorumsCount; + } + auto quorums = llmq::quorumManager->ScanQuorums(params.type, count); for (auto& quorum : quorums) { - for (auto& m : quorum->members) { - if (m->proTxHash == dmn->proTxHash) { - quorumHashes.emplace(params.type, quorum->qc.quorumHash); - } + if (quorum->IsMember(dmn->proTxHash)) { + auto json = BuildQuorumInfo(quorum, false, false); + json.push_back(Pair("isValidMember", quorum->IsValidMember(dmn->proTxHash))); + json.push_back(Pair("memberIndex", quorum->GetMemberIndex(dmn->proTxHash))); + result.push_back(json); } } } - UniValue result(UniValue::VARR); - for (auto& p : quorumHashes) { - auto quorum = llmq::quorumManager->GetQuorum(p.first, p.second); - assert(quorum); - result.push_back(BuildQuorumInfo(quorum, false, false)); - } - return result; } From 013169d63d0057478f5191d5737a585fb19f1396 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2019 07:59:57 +0200 Subject: [PATCH 11/19] Optimize on-disk deterministic masternode storage to reduce size of evodb (#3017) * Implement CompactFull() in CDBWrapper This allows to compact the whole DB in one go. * Implement more compact version of CDeterministicMNListDiff This introduces CDeterministicMNStateDiff which requires to only store fields on-disk which actually changed. * Avoid writing mnUniquePropertyMap to disk when storing snapshots This map can be rebuilt by simply using AddMN for each deserialized MN. * Implement Serialize/Unserialize in CScript This allows us to directly use READWRITE() on scripts and removes the need for the ugly cast to CScriptBase. This commit also changes all Dash specific uses of CScript to not use the cast. * Keep track of registeration counts and introduce internalID for masternodes The "internalId" is simply the number of MNs registered so far when the new MN is added. It is deterministic and stays the same forever. * Use internalId as keys in MN list diffs This reduces the used size on-disk. * Two simple speedups in MN list diff handling 1. Avoid full compare if dmn or state pointers match in BuildDiff 2. Use std::move when adding diff to listDiff in GetListForBlock * Implement upgrade code for old CDeterministicMNListDiff format to new format * Track tipIndex instead of tipHeight/tipBlockHash * Store and pass around CBlockIndex* instead of block hash and height This allows us to switch CDeterministicMNManager::GetListForBlock to work with CBlockIndex. * Refactor CDeterministicMNManager::GetListForBlock to require CBlockIndex* Instead of requiring a block hash. This allows us to remove blockHash and prevBlockHash from CDeterministicMNListDiff without the use of cs_main locks in GetListForBlock. * Remove prevBlockHash, blockHash and nHeight from CDeterministicMNListDiff * Remove access to determinisitcMNManager in CMasternodeMetaMan::ToString() The deterministic MN manager is not fully initialized yet at the time this is called, which results in an empty list being returned everytime. * Better logic to determine if an upgrade is needed Reuse the "best block" logic to figure out if an upgrade is needed. Also use it to ensure that older nodes are unable to start after the upgrade was performed. * Return null block hash if it was requested with getmnlistdiff * bump CGovernanceManager::SERIALIZATION_VERSION_STRING * Check SERIALIZATION_VERSION_STRING before deserializing anything else * Invoke Clear() before deserializing just to be sure --- src/activemasternode.cpp | 2 +- src/dbwrapper.h | 5 + src/evo/deterministicmns.cpp | 265 ++++++++++++++++++++----- src/evo/deterministicmns.h | 264 +++++++++++++++++++----- src/evo/evodb.h | 4 +- src/evo/mnauth.cpp | 10 +- src/evo/providertx.cpp | 8 +- src/evo/providertx.h | 6 +- src/evo/simplifiedmns.cpp | 9 +- src/governance.cpp | 12 +- src/governance.h | 8 +- src/init.cpp | 2 + src/llmq/quorums.cpp | 14 +- src/llmq/quorums.h | 4 +- src/llmq/quorums_blockprocessor.cpp | 9 +- src/llmq/quorums_commitment.cpp | 2 +- src/llmq/quorums_debug.cpp | 13 +- src/llmq/quorums_dkgsession.cpp | 35 ++-- src/llmq/quorums_dkgsession.h | 5 +- src/llmq/quorums_dkgsessionhandler.cpp | 22 +- src/llmq/quorums_dkgsessionhandler.h | 2 +- src/llmq/quorums_dkgsessionmgr.cpp | 22 +- src/llmq/quorums_dkgsessionmgr.h | 8 +- src/llmq/quorums_utils.cpp | 14 +- src/llmq/quorums_utils.h | 6 +- src/masternode-meta.cpp | 1 - src/masternode-meta.h | 8 +- src/masternode-payments.cpp | 8 +- src/rpc/rpcevo.cpp | 4 +- src/rpc/rpcquorums.cpp | 4 +- src/script/script.h | 9 + src/spentindex.h | 2 +- 32 files changed, 569 insertions(+), 218 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 3484c16eb0438..fe51fba07ce60 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -134,7 +134,7 @@ void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, con if (!deterministicMNManager->IsDIP3Enforced(pindexNew->nHeight)) return; if (state == MASTERNODE_READY) { - auto mnList = deterministicMNManager->GetListForBlock(pindexNew->GetBlockHash()); + auto mnList = deterministicMNManager->GetListForBlock(pindexNew); if (!mnList.IsMNValid(mnListEntry->proTxHash)) { // MN disappeared from MN list state = MASTERNODE_REMOVED; diff --git a/src/dbwrapper.h b/src/dbwrapper.h index fc637bea50e97..e434eeeaf3614 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -391,6 +391,11 @@ class CDBWrapper pdb->CompactRange(&slKey1, &slKey2); } + void CompactFull() const + { + pdb->CompactRange(nullptr, nullptr); + } + }; template diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 96bb8086a82e2..673a2156fbc07 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -182,6 +182,15 @@ CDeterministicMNCPtr CDeterministicMNList::GetValidMNByService(const CService& s return dmn; } +CDeterministicMNCPtr CDeterministicMNList::GetMNByInternalId(uint64_t internalId) const +{ + auto proTxHash = mnInternalIdMap.find(internalId); + if (!proTxHash) { + return nullptr; + } + return GetMN(*proTxHash); +} + static int CompareByLastPaid_GetHeight(const CDeterministicMN& dmn) { int height = dmn.pdmnState->nLastPaidHeight; @@ -349,25 +358,31 @@ void CDeterministicMNList::PoSeDecrease(const uint256& proTxHash) CDeterministicMNListDiff CDeterministicMNList::BuildDiff(const CDeterministicMNList& to) const { CDeterministicMNListDiff diffRet; - diffRet.prevBlockHash = blockHash; - diffRet.blockHash = to.blockHash; - diffRet.nHeight = to.nHeight; to.ForEachMN(false, [&](const CDeterministicMNCPtr& toPtr) { auto fromPtr = GetMN(toPtr->proTxHash); if (fromPtr == nullptr) { - diffRet.addedMNs.emplace(toPtr->proTxHash, toPtr); - } else if (*toPtr->pdmnState != *fromPtr->pdmnState) { - diffRet.updatedMNs.emplace(toPtr->proTxHash, toPtr->pdmnState); + diffRet.addedMNs.emplace_back(toPtr); + } else if (fromPtr != toPtr || fromPtr->pdmnState != toPtr->pdmnState) { + CDeterministicMNStateDiff stateDiff(*fromPtr->pdmnState, *toPtr->pdmnState); + if (stateDiff.fields) { + diffRet.updatedMNs.emplace(toPtr->internalId, std::move(stateDiff)); + } } }); ForEachMN(false, [&](const CDeterministicMNCPtr& fromPtr) { auto toPtr = to.GetMN(fromPtr->proTxHash); if (toPtr == nullptr) { - diffRet.removedMns.insert(fromPtr->proTxHash); + diffRet.removedMns.emplace(fromPtr->internalId); } }); + // added MNs need to be sorted by internalId so that these are added in correct order when the diff is applied later + // otherwise internalIds will not match with the original list + std::sort(diffRet.addedMNs.begin(), diffRet.addedMNs.end(), [](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) { + return a->internalId < b->internalId; + }); + return diffRet; } @@ -399,22 +414,25 @@ CSimplifiedMNListDiff CDeterministicMNList::BuildSimplifiedDiff(const CDetermini return diffRet; } -CDeterministicMNList CDeterministicMNList::ApplyDiff(const CDeterministicMNListDiff& diff) const +CDeterministicMNList CDeterministicMNList::ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const { - assert(diff.prevBlockHash == blockHash && diff.nHeight == nHeight + 1); - CDeterministicMNList result = *this; - result.blockHash = diff.blockHash; - result.nHeight = diff.nHeight; + result.blockHash = pindex->GetBlockHash(); + result.nHeight = pindex->nHeight; - for (const auto& hash : diff.removedMns) { - result.RemoveMN(hash); + for (const auto& id : diff.removedMns) { + auto dmn = result.GetMNByInternalId(id); + assert(dmn); + result.RemoveMN(dmn->proTxHash); } - for (const auto& p : diff.addedMNs) { - result.AddMN(p.second); + for (const auto& dmn : diff.addedMNs) { + assert(dmn->internalId == result.GetTotalRegisteredCount()); + result.AddMN(dmn); + result.SetTotalRegisteredCount(result.GetTotalRegisteredCount() + 1); } for (const auto& p : diff.updatedMNs) { - result.UpdateMN(p.first, p.second); + auto dmn = result.GetMNByInternalId(p.first); + result.UpdateMN(dmn, p.second); } return result; @@ -424,6 +442,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn) { assert(!mnMap.find(dmn->proTxHash)); mnMap = mnMap.set(dmn->proTxHash, dmn); + mnInternalIdMap = mnInternalIdMap.set(dmn->internalId, dmn->proTxHash); AddUniqueProperty(dmn, dmn->collateralOutpoint); if (dmn->pdmnState->addr != CService()) { AddUniqueProperty(dmn, dmn->pdmnState->addr); @@ -434,20 +453,35 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn) } } -void CDeterministicMNList::UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState) +void CDeterministicMNList::UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateCPtr& pdmnState) { - auto oldDmn = mnMap.find(proTxHash); assert(oldDmn != nullptr); - auto dmn = std::make_shared(**oldDmn); + auto dmn = std::make_shared(*oldDmn); auto oldState = dmn->pdmnState; dmn->pdmnState = pdmnState; - mnMap = mnMap.set(proTxHash, dmn); + mnMap = mnMap.set(oldDmn->proTxHash, dmn); UpdateUniqueProperty(dmn, oldState->addr, pdmnState->addr); UpdateUniqueProperty(dmn, oldState->keyIDOwner, pdmnState->keyIDOwner); UpdateUniqueProperty(dmn, oldState->pubKeyOperator, pdmnState->pubKeyOperator); } +void CDeterministicMNList::UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState) +{ + auto oldDmn = mnMap.find(proTxHash); + assert(oldDmn != nullptr); + UpdateMN(*oldDmn, pdmnState); +} + +void CDeterministicMNList::UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateDiff& stateDiff) +{ + assert(oldDmn != nullptr); + auto oldState = oldDmn->pdmnState; + auto newState = std::make_shared(*oldState); + stateDiff.ApplyToState(*newState); + UpdateMN(oldDmn, newState); +} + void CDeterministicMNList::RemoveMN(const uint256& proTxHash) { auto dmn = GetMN(proTxHash); @@ -461,6 +495,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash) DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator); } mnMap = mnMap.erase(proTxHash); + mnInternalIdMap = mnInternalIdMap.erase(dmn->internalId); } CDeterministicMNManager::CDeterministicMNManager(CEvoDB& _evoDb) : @@ -500,12 +535,12 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde newList.SetBlockHash(block.GetHash()); - oldList = GetListForBlock(pindex->pprev->GetBlockHash()); + oldList = GetListForBlock(pindex->pprev); diff = oldList.BuildDiff(newList); - evoDb.Write(std::make_pair(DB_LIST_DIFF, diff.blockHash), diff); + evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff); if ((nHeight % SNAPSHOT_LIST_PERIOD) == 0 || oldList.GetHeight() == -1) { - evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, diff.blockHash), newList); + evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList); LogPrintf("CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n", __func__, nHeight, newList.GetAllMNsCount()); } @@ -546,8 +581,8 @@ bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex* if (diff.HasChanges()) { // need to call this before erasing - curList = GetListForBlock(blockHash); - prevList = GetListForBlock(pindex->pprev->GetBlockHash()); + curList = GetListForBlock(pindex); + prevList = GetListForBlock(pindex->pprev); } evoDb.Erase(std::make_pair(DB_LIST_DIFF, blockHash)); @@ -574,8 +609,7 @@ void CDeterministicMNManager::UpdatedBlockTip(const CBlockIndex* pindex) { LOCK(cs); - tipHeight = pindex->nHeight; - tipBlockHash = pindex->GetBlockHash(); + tipIndex = pindex; } bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& _state, CDeterministicMNList& mnListRet, bool debugLogs) @@ -584,7 +618,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C int nHeight = pindexPrev->nHeight + 1; - CDeterministicMNList oldList = GetListForBlock(pindexPrev->GetBlockHash()); + CDeterministicMNList oldList = GetListForBlock(pindexPrev); CDeterministicMNList newList = oldList; newList.SetBlockHash(uint256()); // we can't know the final block hash, so better not return a (invalid) block hash newList.SetHeight(nHeight); @@ -628,6 +662,8 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C auto dmn = std::make_shared(); dmn->proTxHash = tx.GetHash(); + dmn->internalId = newList.GetTotalRegisteredCount(); + newList.SetTotalRegisteredCount(newList.GetTotalRegisteredCount() + 1); // collateralOutpoint is either pointing to an external collateral or to the ProRegTx itself if (proTx.collateralOutpoint.hash.IsNull()) { @@ -771,7 +807,15 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C assert(false); // this should have been handled already } if (!qc.commitment.IsNull()) { - HandleQuorumCommitment(qc.commitment, newList, debugLogs); + const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)qc.commitment.llmqType); + int quorumHeight = qc.nHeight - (qc.nHeight % params.dkgInterval); + auto quorumIndex = pindexPrev->GetAncestor(quorumHeight); + if (!quorumIndex || quorumIndex->GetBlockHash() != qc.commitment.quorumHash) { + // we should actually never get into this case as validation should have catched it...but lets be sure + return _state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash"); + } + + HandleQuorumCommitment(qc.commitment, quorumIndex, newList, debugLogs); } } } @@ -807,11 +851,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C return true; } -void CDeterministicMNManager::HandleQuorumCommitment(llmq::CFinalCommitment& qc, CDeterministicMNList& mnList, bool debugLogs) +void CDeterministicMNManager::HandleQuorumCommitment(llmq::CFinalCommitment& qc, const CBlockIndex* pindexQuorum, CDeterministicMNList& mnList, bool debugLogs) { // The commitment has already been validated at this point so it's safe to use members of it - auto members = llmq::CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, qc.quorumHash); + auto members = llmq::CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum); for (size_t i = 0; i < members.size(); i++) { if (!mnList.HasMN(members[i]->proTxHash)) { @@ -844,52 +888,48 @@ void CDeterministicMNManager::DecreasePoSePenalties(CDeterministicMNList& mnList } } -CDeterministicMNList CDeterministicMNManager::GetListForBlock(const uint256& blockHash) +CDeterministicMNList CDeterministicMNManager::GetListForBlock(const CBlockIndex* pindex) { LOCK(cs); - auto it = mnListsCache.find(blockHash); - if (it != mnListsCache.end()) { - return it->second; - } - - uint256 blockHashTmp = blockHash; CDeterministicMNList snapshot; - std::list listDiff; + std::list> listDiff; while (true) { // try using cache before reading from disk - it = mnListsCache.find(blockHashTmp); + auto it = mnListsCache.find(pindex->GetBlockHash()); if (it != mnListsCache.end()) { snapshot = it->second; break; } - if (evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, blockHashTmp), snapshot)) { - mnListsCache.emplace(blockHashTmp, snapshot); + if (evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot)) { + mnListsCache.emplace(pindex->GetBlockHash(), snapshot); break; } CDeterministicMNListDiff diff; - if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHashTmp), diff)) { - snapshot = CDeterministicMNList(blockHashTmp, -1); - mnListsCache.emplace(blockHashTmp, snapshot); + if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), diff)) { + snapshot = CDeterministicMNList(pindex->GetBlockHash(), -1, 0); + mnListsCache.emplace(pindex->GetBlockHash(), snapshot); break; } - listDiff.emplace_front(diff); - blockHashTmp = diff.prevBlockHash; + listDiff.emplace_front(pindex, std::move(diff)); + pindex = pindex->pprev; } - for (const auto& diff : listDiff) { + for (const auto& p : listDiff) { + auto diffIndex = p.first; + auto& diff = p.second; if (diff.HasChanges()) { - snapshot = snapshot.ApplyDiff(diff); + snapshot = snapshot.ApplyDiff(diffIndex, diff); } else { - snapshot.SetBlockHash(diff.blockHash); - snapshot.SetHeight(diff.nHeight); + snapshot.SetBlockHash(diffIndex->GetBlockHash()); + snapshot.SetHeight(diffIndex->nHeight); } - mnListsCache.emplace(diff.blockHash, snapshot); + mnListsCache.emplace(diffIndex->GetBlockHash(), snapshot); } return snapshot; @@ -898,7 +938,10 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const uint256& blo CDeterministicMNList CDeterministicMNManager::GetListAtChainTip() { LOCK(cs); - return GetListForBlock(tipBlockHash); + if (!tipIndex) { + return {}; + } + return GetListForBlock(tipIndex); } bool CDeterministicMNManager::IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n) @@ -928,7 +971,7 @@ bool CDeterministicMNManager::IsDIP3Enforced(int nHeight) LOCK(cs); if (nHeight == -1) { - nHeight = tipHeight; + nHeight = tipIndex->nHeight; } return nHeight >= Params().GetConsensus().DIP0003EnforcementHeight; @@ -948,3 +991,115 @@ void CDeterministicMNManager::CleanupCache(int nHeight) mnListsCache.erase(h); } } + +bool CDeterministicMNManager::UpgradeDiff(CDBBatch& batch, const CBlockIndex* pindexNext, const CDeterministicMNList& curMNList, CDeterministicMNList& newMNList) +{ + CDataStream oldDiffData(SER_DISK, CLIENT_VERSION); + if (!evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_LIST_DIFF, pindexNext->GetBlockHash()), oldDiffData)) { + LogPrintf("CDeterministicMNManager::%s -- no diff found for %s\n", __func__, pindexNext->GetBlockHash().ToString()); + newMNList = curMNList; + newMNList.SetBlockHash(pindexNext->GetBlockHash()); + newMNList.SetHeight(pindexNext->nHeight); + return false; + } + + CDeterministicMNListDiff_OldFormat oldDiff; + oldDiffData >> oldDiff; + + CDeterministicMNListDiff newDiff; + size_t addedCount = 0; + for (auto& p : oldDiff.addedMNs) { + auto dmn = std::make_shared(*p.second); + dmn->internalId = curMNList.GetTotalRegisteredCount() + addedCount; + newDiff.addedMNs.emplace_back(dmn); + + addedCount++; + } + for (auto& p : oldDiff.removedMns) { + auto dmn = curMNList.GetMN(p); + newDiff.removedMns.emplace(dmn->internalId); + } + + // applies added/removed MNs + newMNList = curMNList.ApplyDiff(pindexNext, newDiff); + + // manually apply updated MNs and calc new state diffs + for (auto& p : oldDiff.updatedMNs) { + auto oldMN = newMNList.GetMN(p.first); + newMNList.UpdateMN(p.first, p.second); + auto newMN = newMNList.GetMN(p.first); + assert(oldMN && newMN); + + newDiff.updatedMNs.emplace(std::piecewise_construct, + std::forward_as_tuple(oldMN->internalId), + std::forward_as_tuple(*oldMN->pdmnState, *newMN->pdmnState)); + } + + batch.Write(std::make_pair(DB_LIST_DIFF, pindexNext->GetBlockHash()), newDiff); + + return true; +} + +// TODO this can be completely removed in a future version +void CDeterministicMNManager::UpgradeDBIfNeeded() +{ + LOCK(cs_main); + + if (chainActive.Tip() == nullptr) { + return; + } + + if (evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK)) { + return; + } + + // Removing the old EVODB_BEST_BLOCK value early results in older version to crash immediately, even if the upgrade + // process is cancelled in-between. But if the new version sees that the old EVODB_BEST_BLOCK is already removed, + // then we must assume that the upgrade process was already running before but was interrupted. + if (chainActive.Height() > 1 && !evoDb.GetRawDB().Exists(std::string("b_b"))) { + LogPrintf("CDeterministicMNManager::%s -- ERROR, upgrade process was interrupted and can't be continued. You need to reindex now.\n", __func__); + } + evoDb.GetRawDB().Erase(std::string("b_b")); + + if (chainActive.Height() < Params().GetConsensus().DIP0003Height) { + // not reached DIP3 height yet, so no upgrade needed + auto dbTx = evoDb.BeginTransaction(); + evoDb.WriteBestBlock(chainActive.Tip()->GetBlockHash()); + dbTx->Commit(); + return; + } + + LogPrintf("CDeterministicMNManager::%s -- upgrading DB to use compact diffs\n", __func__); + + CDBBatch batch(evoDb.GetRawDB()); + + CDeterministicMNList curMNList; + curMNList.SetHeight(Params().GetConsensus().DIP0003Height - 1); + curMNList.SetBlockHash(chainActive[Params().GetConsensus().DIP0003Height - 1]->GetBlockHash()); + + for (int nHeight = Params().GetConsensus().DIP0003Height; nHeight <= chainActive.Height(); nHeight++) { + auto pindex = chainActive[nHeight]; + + CDeterministicMNList newMNList; + UpgradeDiff(batch, pindex, curMNList, newMNList); + + if ((nHeight % SNAPSHOT_LIST_PERIOD) == 0) { + batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), newMNList); + evoDb.GetRawDB().WriteBatch(batch); + batch.Clear(); + } + + curMNList = newMNList; + } + + evoDb.GetRawDB().WriteBatch(batch); + + LogPrintf("CDeterministicMNManager::%s -- done upgrading\n", __func__); + + // Writing EVODB_BEST_BLOCK (which is b_b2 now) marks the DB as upgraded + auto dbTx = evoDb.BeginTransaction(); + evoDb.WriteBestBlock(chainActive.Tip()->GetBlockHash()); + dbTx->Commit(); + + evoDb.GetRawDB().CompactFull(); +} diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index 62cf3bed256af..7ba5146617390 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -83,8 +83,8 @@ class CDeterministicMNState READWRITE(pubKeyOperator); READWRITE(keyIDVoting); READWRITE(addr); - READWRITE(*(CScriptBase*)(&scriptPayout)); - READWRITE(*(CScriptBase*)(&scriptOperatorPayout)); + READWRITE(scriptPayout); + READWRITE(scriptOperatorPayout); } void ResetOperatorFields() @@ -109,35 +109,81 @@ class CDeterministicMNState h.Finalize(confirmedHashWithProRegTxHash.begin()); } - bool operator==(const CDeterministicMNState& rhs) const +public: + std::string ToString() const; + void ToJson(UniValue& obj) const; +}; +typedef std::shared_ptr CDeterministicMNStatePtr; +typedef std::shared_ptr CDeterministicMNStateCPtr; + +class CDeterministicMNStateDiff +{ +public: + enum Field : uint32_t { + Field_nRegisteredHeight = 0x0001, + Field_nLastPaidHeight = 0x0002, + Field_nPoSePenalty = 0x0004, + Field_nPoSeRevivedHeight = 0x0008, + Field_nPoSeBanHeight = 0x0010, + Field_nRevocationReason = 0x0020, + Field_confirmedHash = 0x0040, + Field_confirmedHashWithProRegTxHash = 0x0080, + Field_keyIDOwner = 0x0100, + Field_pubKeyOperator = 0x0200, + Field_keyIDVoting = 0x0400, + Field_addr = 0x0800, + Field_scriptPayout = 0x1000, + Field_scriptOperatorPayout = 0x2000, + }; + +#define DMN_STATE_DIFF_ALL_FIELDS \ + DMN_STATE_DIFF_LINE(nRegisteredHeight) \ + DMN_STATE_DIFF_LINE(nLastPaidHeight) \ + DMN_STATE_DIFF_LINE(nPoSePenalty) \ + DMN_STATE_DIFF_LINE(nPoSeRevivedHeight) \ + DMN_STATE_DIFF_LINE(nPoSeBanHeight) \ + DMN_STATE_DIFF_LINE(nRevocationReason) \ + DMN_STATE_DIFF_LINE(confirmedHash) \ + DMN_STATE_DIFF_LINE(confirmedHashWithProRegTxHash) \ + DMN_STATE_DIFF_LINE(keyIDOwner) \ + DMN_STATE_DIFF_LINE(pubKeyOperator) \ + DMN_STATE_DIFF_LINE(keyIDVoting) \ + DMN_STATE_DIFF_LINE(addr) \ + DMN_STATE_DIFF_LINE(scriptPayout) \ + DMN_STATE_DIFF_LINE(scriptOperatorPayout) + +public: + uint32_t fields{0}; + // we reuse the state class, but only the members as noted by fields are valid + CDeterministicMNState state; + +public: + CDeterministicMNStateDiff() {} + CDeterministicMNStateDiff(const CDeterministicMNState& a, const CDeterministicMNState& b) { - return nRegisteredHeight == rhs.nRegisteredHeight && - nLastPaidHeight == rhs.nLastPaidHeight && - nPoSePenalty == rhs.nPoSePenalty && - nPoSeRevivedHeight == rhs.nPoSeRevivedHeight && - nPoSeBanHeight == rhs.nPoSeBanHeight && - nRevocationReason == rhs.nRevocationReason && - confirmedHash == rhs.confirmedHash && - confirmedHashWithProRegTxHash == rhs.confirmedHashWithProRegTxHash && - keyIDOwner == rhs.keyIDOwner && - pubKeyOperator == rhs.pubKeyOperator && - keyIDVoting == rhs.keyIDVoting && - addr == rhs.addr && - scriptPayout == rhs.scriptPayout && - scriptOperatorPayout == rhs.scriptOperatorPayout; +#define DMN_STATE_DIFF_LINE(f) if (a.f != b.f) { state.f = b.f; fields |= Field_##f; } + DMN_STATE_DIFF_ALL_FIELDS +#undef DMN_STATE_DIFF_LINE } - bool operator!=(const CDeterministicMNState& rhs) const + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { - return !(rhs == *this); + READWRITE(VARINT(fields)); +#define DMN_STATE_DIFF_LINE(f) if (fields & Field_##f) READWRITE(state.f); + DMN_STATE_DIFF_ALL_FIELDS +#undef DMN_STATE_DIFF_LINE } -public: - std::string ToString() const; - void ToJson(UniValue& obj) const; + void ApplyToState(CDeterministicMNState& target) const + { +#define DMN_STATE_DIFF_LINE(f) if (fields & Field_##f) target.f = state.f; + DMN_STATE_DIFF_ALL_FIELDS +#undef DMN_STATE_DIFF_LINE + } }; -typedef std::shared_ptr CDeterministicMNStatePtr; -typedef std::shared_ptr CDeterministicMNStateCPtr; class CDeterministicMN { @@ -150,22 +196,36 @@ class CDeterministicMN } uint256 proTxHash; + uint64_t internalId{std::numeric_limits::max()}; COutPoint collateralOutpoint; uint16_t nOperatorReward; CDeterministicMNStateCPtr pdmnState; public: - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) + inline void SerializationOp(Stream& s, Operation ser_action, bool oldFormat) { READWRITE(proTxHash); + if (!oldFormat) { + READWRITE(VARINT(internalId)); + } READWRITE(collateralOutpoint); READWRITE(nOperatorReward); READWRITE(pdmnState); } + template + void Serialize(Stream& s) const + { + NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), false); + } + + template + void Unserialize(Stream& s, bool oldFormat = false) + { + SerializationOp(s, CSerActionUnserialize(), oldFormat); + } + public: std::string ToString() const; void ToJson(UniValue& obj) const; @@ -214,35 +274,60 @@ class CDeterministicMNList { public: typedef immer::map MnMap; + typedef immer::map MnInternalIdMap; typedef immer::map > MnUniquePropertyMap; private: uint256 blockHash; int nHeight{-1}; + uint32_t nTotalRegisteredCount{0}; MnMap mnMap; + MnInternalIdMap mnInternalIdMap; // map of unique properties like address and keys // we keep track of this as checking for duplicates would otherwise be painfully slow - // the entries in the map are ref counted as some properties might appear multiple times per MN (e.g. operator/owner keys) MnUniquePropertyMap mnUniquePropertyMap; public: CDeterministicMNList() {} - explicit CDeterministicMNList(const uint256& _blockHash, int _height) : + explicit CDeterministicMNList(const uint256& _blockHash, int _height, uint32_t _totalRegisteredCount) : blockHash(_blockHash), - nHeight(_height) + nHeight(_height), + nTotalRegisteredCount(_totalRegisteredCount) { } - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) + inline void SerializationOpBase(Stream& s, Operation ser_action) { READWRITE(blockHash); READWRITE(nHeight); - READWRITE(mnMap); - READWRITE(mnUniquePropertyMap); + READWRITE(nTotalRegisteredCount); + } + + template + void Serialize(Stream& s) const + { + NCONST_PTR(this)->SerializationOpBase(s, CSerActionSerialize()); + // Serialize the map as a vector + WriteCompactSize(s, mnMap.size()); + for (const auto& p : mnMap) { + s << *p.second; + } + } + + template + void Unserialize(Stream& s) { + mnMap = MnMap(); + mnUniquePropertyMap = MnUniquePropertyMap(); + mnInternalIdMap = MnInternalIdMap(); + + SerializationOpBase(s, CSerActionUnserialize()); + + size_t cnt = ReadCompactSize(s); + for (size_t i = 0; i < cnt; i++) { + AddMN(std::make_shared(deserialize, s)); + } } public: @@ -289,6 +374,14 @@ class CDeterministicMNList { nHeight = _height; } + uint32_t GetTotalRegisteredCount() const + { + return nTotalRegisteredCount; + } + void SetTotalRegisteredCount(uint32_t _count) + { + nTotalRegisteredCount = _count; + } bool IsMNValid(const uint256& proTxHash) const; bool IsMNPoSeBanned(const uint256& proTxHash) const; @@ -318,6 +411,7 @@ class CDeterministicMNList CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const; CDeterministicMNCPtr GetMNByService(const CService& service) const; CDeterministicMNCPtr GetValidMNByService(const CService& service) const; + CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const; CDeterministicMNCPtr GetMNPayee() const; /** @@ -372,10 +466,12 @@ class CDeterministicMNList CDeterministicMNListDiff BuildDiff(const CDeterministicMNList& to) const; CSimplifiedMNListDiff BuildSimplifiedDiff(const CDeterministicMNList& to) const; - CDeterministicMNList ApplyDiff(const CDeterministicMNListDiff& diff) const; + CDeterministicMNList ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const; void AddMN(const CDeterministicMNCPtr& dmn); + void UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateCPtr& pdmnState); void UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState); + void UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateDiff& stateDiff); void RemoveMN(const uint256& proTxHash); template @@ -445,25 +541,48 @@ class CDeterministicMNList class CDeterministicMNListDiff { public: - uint256 prevBlockHash; - uint256 blockHash; - int nHeight{-1}; - std::map addedMNs; - std::map updatedMNs; - std::set removedMns; + std::vector addedMNs; + // keys are all relating to the internalId of MNs + std::map updatedMNs; + std::set removedMns; public: - ADD_SERIALIZE_METHODS; + template + void Serialize(Stream& s) const + { + s << addedMNs; + WriteCompactSize(s, updatedMNs.size()); + for (const auto& p : updatedMNs) { + WriteVarInt(s, p.first); + s << p.second; + } + WriteCompactSize(s, removedMns.size()); + for (const auto& p : removedMns) { + WriteVarInt(s, p); + } + } - template - inline void SerializationOp(Stream& s, Operation ser_action) + template + void Unserialize(Stream& s) { - READWRITE(prevBlockHash); - READWRITE(blockHash); - READWRITE(nHeight); - READWRITE(addedMNs); - READWRITE(updatedMNs); - READWRITE(removedMns); + updatedMNs.clear(); + removedMns.clear(); + + size_t tmp; + uint64_t tmp2; + s >> addedMNs; + tmp = ReadCompactSize(s); + for (size_t i = 0; i < tmp; i++) { + CDeterministicMNStateDiff diff; + tmp2 = ReadVarInt(s); + s >> diff; + updatedMNs.emplace(tmp2, std::move(diff)); + } + tmp = ReadCompactSize(s); + for (size_t i = 0; i < tmp; i++) { + tmp2 = ReadVarInt(s); + removedMns.emplace(tmp2); + } } public: @@ -473,6 +592,37 @@ class CDeterministicMNListDiff } }; +// TODO can be removed in a future version +class CDeterministicMNListDiff_OldFormat +{ +public: + uint256 prevBlockHash; + uint256 blockHash; + int nHeight{-1}; + std::map addedMNs; + std::map updatedMNs; + std::set removedMns; + +public: + template + void Unserialize(Stream& s) { + addedMNs.clear(); + s >> prevBlockHash; + s >> blockHash; + s >> nHeight; + size_t cnt = ReadCompactSize(s); + for (size_t i = 0; i < cnt; i++) { + uint256 proTxHash; + auto dmn = std::make_shared(); + s >> proTxHash; + dmn->Unserialize(s, true); + addedMNs.emplace(proTxHash, dmn); + } + s >> updatedMNs; + s >> removedMns; + } +}; + class CDeterministicMNManager { static const int SNAPSHOT_LIST_PERIOD = 576; // once per day @@ -485,8 +635,7 @@ class CDeterministicMNManager CEvoDB& evoDb; std::map mnListsCache; - int tipHeight{-1}; - uint256 tipBlockHash; + const CBlockIndex* tipIndex{nullptr}; public: CDeterministicMNManager(CEvoDB& _evoDb); @@ -498,10 +647,10 @@ class CDeterministicMNManager // the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet) bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& state, CDeterministicMNList& mnListRet, bool debugLogs); - void HandleQuorumCommitment(llmq::CFinalCommitment& qc, CDeterministicMNList& mnList, bool debugLogs); + void HandleQuorumCommitment(llmq::CFinalCommitment& qc, const CBlockIndex* pindexQuorum, CDeterministicMNList& mnList, bool debugLogs); void DecreasePoSePenalties(CDeterministicMNList& mnList); - CDeterministicMNList GetListForBlock(const uint256& blockHash); + CDeterministicMNList GetListForBlock(const CBlockIndex* pindex); CDeterministicMNList GetListAtChainTip(); // Test if given TX is a ProRegTx which also contains the collateral at index n @@ -509,6 +658,11 @@ class CDeterministicMNManager bool IsDIP3Enforced(int nHeight = -1); +public: + // TODO these can all be removed in a future version + bool UpgradeDiff(CDBBatch& batch, const CBlockIndex* pindexNext, const CDeterministicMNList& curMNList, CDeterministicMNList& newMNList); + void UpgradeDBIfNeeded(); + private: void CleanupCache(int nHeight); }; diff --git a/src/evo/evodb.h b/src/evo/evodb.h index 03e9b3acfde12..b5f282d357251 100644 --- a/src/evo/evodb.h +++ b/src/evo/evodb.h @@ -9,7 +9,9 @@ #include "sync.h" #include "uint256.h" -static const std::string EVODB_BEST_BLOCK = "b_b"; +// "b_b" was used in the initial version of deterministic MN storage +// "b_b2" was used after compact diffs were introduced +static const std::string EVODB_BEST_BLOCK = "b_b2"; class CEvoDB { diff --git a/src/evo/mnauth.cpp b/src/evo/mnauth.cpp index a8aed3fd40fba..e5f0c44e6694d 100644 --- a/src/evo/mnauth.cpp +++ b/src/evo/mnauth.cpp @@ -127,13 +127,17 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& if (pnode->verifiedProRegTxHash.IsNull()) { return; } + auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash); + if (!verifiedDmn) { + return; + } bool doRemove = false; - if (diff.removedMns.count(pnode->verifiedProRegTxHash)) { + if (diff.removedMns.count(verifiedDmn->internalId)) { doRemove = true; } else { - auto it = diff.updatedMNs.find(pnode->verifiedProRegTxHash); + auto it = diff.updatedMNs.find(verifiedDmn->internalId); if (it != diff.updatedMNs.end()) { - if (it->second->pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) { + if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) { doRemove = true; } } diff --git a/src/evo/providertx.cpp b/src/evo/providertx.cpp index 019f427f68d14..02dc664e70746 100644 --- a/src/evo/providertx.cpp +++ b/src/evo/providertx.cpp @@ -174,7 +174,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid } if (pindexPrev) { - auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash()); + auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); // only allow reusing of addresses when it's for the same collateral (which replaces the old MN) if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) { @@ -232,7 +232,7 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa } if (pindexPrev) { - auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash()); + auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto mn = mnList.GetMN(ptx.proTxHash); if (!mn) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash"); @@ -297,7 +297,7 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal } if (pindexPrev) { - auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash()); + auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto dmn = mnList.GetMN(ptx.proTxHash); if (!dmn) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash"); @@ -369,7 +369,7 @@ bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal } if (pindexPrev) { - auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash()); + auto mnList = deterministicMNManager->GetListForBlock(pindexPrev); auto dmn = mnList.GetMN(ptx.proTxHash); if (!dmn) return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash"); diff --git a/src/evo/providertx.h b/src/evo/providertx.h index bb5c0f18ebc0a..b7eb6fe87cc96 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -49,7 +49,7 @@ class CProRegTx READWRITE(pubKeyOperator); READWRITE(keyIDVoting); READWRITE(nOperatorReward); - READWRITE(*(CScriptBase*)(&scriptPayout)); + READWRITE(scriptPayout); READWRITE(inputsHash); if (!(s.GetType() & SER_GETHASH)) { READWRITE(vchSig); @@ -86,7 +86,7 @@ class CProUpServTx READWRITE(nVersion); READWRITE(proTxHash); READWRITE(addr); - READWRITE(*(CScriptBase*)(&scriptOperatorPayout)); + READWRITE(scriptOperatorPayout); READWRITE(inputsHash); if (!(s.GetType() & SER_GETHASH)) { READWRITE(sig); @@ -124,7 +124,7 @@ class CProUpRegTx READWRITE(nMode); READWRITE(pubKeyOperator); READWRITE(keyIDVoting); - READWRITE(*(CScriptBase*)(&scriptPayout)); + READWRITE(scriptPayout); READWRITE(inputsHash); if (!(s.GetType() & SER_GETHASH)) { READWRITE(vchSig); diff --git a/src/evo/simplifiedmns.cpp b/src/evo/simplifiedmns.cpp index 10c0d59b4c848..db272d02e0a0b 100644 --- a/src/evo/simplifiedmns.cpp +++ b/src/evo/simplifiedmns.cpp @@ -217,10 +217,15 @@ bool BuildSimplifiedMNListDiff(const uint256& baseBlockHash, const uint256& bloc LOCK(deterministicMNManager->cs); - auto baseDmnList = deterministicMNManager->GetListForBlock(baseBlockHash); - auto dmnList = deterministicMNManager->GetListForBlock(blockHash); + auto baseDmnList = deterministicMNManager->GetListForBlock(baseBlockIndex); + auto dmnList = deterministicMNManager->GetListForBlock(blockIndex); mnListDiffRet = baseDmnList.BuildSimplifiedDiff(dmnList); + // We need to return the value that was provided by the other peer as it otherwise won't be able to recognize the + // response. This will usually be identical to the block found in baseBlockIndex. The only difference is when a + // null block hash was provided to get the diff from the genesis block. + mnListDiffRet.baseBlockHash = baseBlockHash; + if (!mnListDiffRet.BuildQuorumsDiff(baseBlockIndex, blockIndex)) { errorRet = strprintf("failed to build quorums diff"); return false; diff --git a/src/governance.cpp b/src/governance.cpp index 18a2b11812a19..46a09b44a7522 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -24,7 +24,7 @@ CGovernanceManager governance; int nSubmittedFinalBudget; -const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-14"; +const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-15"; const int CGovernanceManager::MAX_TIME_FUTURE_DEVIATION = 60 * 60; const int CGovernanceManager::RELIABLE_PROPAGATION_TIME = 60; @@ -1337,15 +1337,15 @@ void CGovernanceManager::RemoveInvalidVotes() std::vector changedKeyMNs; for (const auto& p : diff.updatedMNs) { - auto oldDmn = lastMNListForVotingKeys.GetMN(p.first); - if (p.second->keyIDVoting != oldDmn->pdmnState->keyIDVoting) { + auto oldDmn = lastMNListForVotingKeys.GetMNByInternalId(p.first); + if ((p.second.fields & CDeterministicMNStateDiff::Field_keyIDVoting) && p.second.state.keyIDVoting != oldDmn->pdmnState->keyIDVoting) { changedKeyMNs.emplace_back(oldDmn->collateralOutpoint); - } else if (p.second->pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) { + } else if ((p.second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && p.second.state.pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) { changedKeyMNs.emplace_back(oldDmn->collateralOutpoint); } } - for (const auto& proTxHash : diff.removedMns) { - auto oldDmn = lastMNListForVotingKeys.GetMN(proTxHash); + for (const auto& id : diff.removedMns) { + auto oldDmn = lastMNListForVotingKeys.GetMNByInternalId(id); changedKeyMNs.emplace_back(oldDmn->collateralOutpoint); } diff --git a/src/governance.h b/src/governance.h index 466b0f971013c..968960f60eae0 100644 --- a/src/governance.h +++ b/src/governance.h @@ -342,7 +342,11 @@ class CGovernanceManager LOCK(cs); std::string strVersion; if (ser_action.ForRead()) { + Clear(); READWRITE(strVersion); + if (strVersion != SERIALIZATION_VERSION_STRING) { + return; + } } else { strVersion = SERIALIZATION_VERSION_STRING; READWRITE(strVersion); @@ -354,10 +358,6 @@ class CGovernanceManager READWRITE(mapObjects); READWRITE(mapLastMasternodeObject); READWRITE(lastMNListForVotingKeys); - if (ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { - Clear(); - return; - } } void UpdatedBlockTip(const CBlockIndex* pindex, CConnman& connman); diff --git a/src/init.cpp b/src/init.cpp index 65101215625f1..246b1f963ee33 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1831,6 +1831,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) break; } + deterministicMNManager->UpgradeDBIfNeeded(); + uiInterface.InitMessage(_("Verifying blocks...")); if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks", diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index f739053b72c63..ec938f0a1c91c 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -49,10 +49,10 @@ CQuorum::~CQuorum() } } -void CQuorum::Init(const CFinalCommitment& _qc, int _height, const uint256& _minedBlockHash, const std::vector& _members) +void CQuorum::Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector& _members) { qc = _qc; - height = _height; + pindexQuorum = _pindexQuorum; members = _members; minedBlockHash = _minedBlockHash; } @@ -193,9 +193,9 @@ void CQuorumManager::EnsureQuorumConnections(Consensus::LLMQType llmqType, const if (!g_connman->HasMasternodeQuorumNodes(llmqType, quorum->qc.quorumHash)) { std::set connections; if (quorum->IsMember(myProTxHash)) { - connections = CLLMQUtils::GetQuorumConnections(llmqType, quorum->qc.quorumHash, myProTxHash); + connections = CLLMQUtils::GetQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash); } else { - auto cindexes = CLLMQUtils::CalcDeterministicWatchConnections(llmqType, quorum->qc.quorumHash, quorum->members.size(), 1); + auto cindexes = CLLMQUtils::CalcDeterministicWatchConnections(llmqType, quorum->pindexQuorum, quorum->members.size(), 1); for (auto idx : cindexes) { connections.emplace(quorum->members[idx]->proTxHash); } @@ -231,9 +231,9 @@ bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const assert(pindexQuorum); assert(qc.quorumHash == pindexQuorum->GetBlockHash()); - auto members = CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, qc.quorumHash); + auto members = CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum); - quorum->Init(qc, pindexQuorum->nHeight, minedBlockHash, members); + quorum->Init(qc, pindexQuorum, minedBlockHash, members); bool hasValidVvec = false; if (quorum->ReadContributions(evoDb)) { @@ -262,7 +262,7 @@ bool CQuorumManager::BuildQuorumContributions(const CFinalCommitment& fqc, std:: std::vector memberIndexes; std::vector vvecs; BLSSecretKeyVector skContributions; - if (!dkgManager.GetVerifiedContributions((Consensus::LLMQType)fqc.llmqType, fqc.quorumHash, fqc.validMembers, memberIndexes, vvecs, skContributions)) { + if (!dkgManager.GetVerifiedContributions((Consensus::LLMQType)fqc.llmqType, quorum->pindexQuorum, fqc.validMembers, memberIndexes, vvecs, skContributions)) { return false; } diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index 8adaf5f440837..37da0f0d5f115 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -37,7 +37,7 @@ class CQuorum public: const Consensus::LLMQParams& params; CFinalCommitment qc; - int height; + const CBlockIndex* pindexQuorum; uint256 minedBlockHash; std::vector members; @@ -55,7 +55,7 @@ class CQuorum public: CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker) : params(_params), blsCache(_blsWorker), stopCachePopulatorThread(false) {} ~CQuorum(); - void Init(const CFinalCommitment& _qc, int _height, const uint256& _minedBlockHash, const std::vector& _members); + void Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector& _members); bool IsMember(const uint256& proTxHash) const; bool IsValidMember(const uint256& proTxHash) const; diff --git a/src/llmq/quorums_blockprocessor.cpp b/src/llmq/quorums_blockprocessor.cpp index eb0c3ba276d43..c24170c283863 100644 --- a/src/llmq/quorums_blockprocessor.cpp +++ b/src/llmq/quorums_blockprocessor.cpp @@ -57,6 +57,7 @@ void CQuorumBlockProcessor::ProcessMessage(CNode* pfrom, const std::string& strC const auto& params = Params().GetConsensus().llmqs.at(type); // Verify that quorumHash is part of the active chain and that it's the first block in the DKG interval + const CBlockIndex* pquorumIndex; { LOCK(cs_main); if (!mapBlockIndex.count(qc.quorumHash)) { @@ -66,7 +67,7 @@ void CQuorumBlockProcessor::ProcessMessage(CNode* pfrom, const std::string& strC // fully synced return; } - auto pquorumIndex = mapBlockIndex[qc.quorumHash]; + pquorumIndex = mapBlockIndex[qc.quorumHash]; if (chainActive.Tip()->GetAncestor(pquorumIndex->nHeight) != pquorumIndex) { LogPrintf("CQuorumBlockProcessor::%s -- block %s not in active chain, peer=%d\n", __func__, qc.quorumHash.ToString(), pfrom->id); @@ -98,7 +99,7 @@ void CQuorumBlockProcessor::ProcessMessage(CNode* pfrom, const std::string& strC } } - auto members = CLLMQUtils::GetAllQuorumMembers(type, qc.quorumHash); + auto members = CLLMQUtils::GetAllQuorumMembers(type, pquorumIndex); if (!qc.Verify(members, true)) { LOCK(cs_main); @@ -203,14 +204,14 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH return state.DoS(100, false, REJECT_INVALID, "bad-qc-height"); } - auto members = CLLMQUtils::GetAllQuorumMembers(params.type, quorumHash); + auto quorumIndex = mapBlockIndex.at(qc.quorumHash); + auto members = CLLMQUtils::GetAllQuorumMembers(params.type, quorumIndex); if (!qc.Verify(members, true)) { return state.DoS(100, false, REJECT_INVALID, "bad-qc-invalid"); } // Store commitment in DB - auto quorumIndex = mapBlockIndex.at(qc.quorumHash); evoDb.Write(std::make_pair(DB_MINED_COMMITMENT, std::make_pair((uint8_t)params.type, quorumHash)), std::make_pair(qc, blockHash)); evoDb.Write(BuildInversedHeightKey(params.type, nHeight), quorumIndex->nHeight); diff --git a/src/llmq/quorums_commitment.cpp b/src/llmq/quorums_commitment.cpp index 5f84ab9429dd2..85ef4bfa33e32 100644 --- a/src/llmq/quorums_commitment.cpp +++ b/src/llmq/quorums_commitment.cpp @@ -193,7 +193,7 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, return true; } - auto members = CLLMQUtils::GetAllQuorumMembers(params.type, qcTx.commitment.quorumHash); + auto members = CLLMQUtils::GetAllQuorumMembers(params.type, pindexQuorum); if (!qcTx.commitment.Verify(members, false)) { return state.DoS(100, false, REJECT_INVALID, "bad-qc-invalid"); } diff --git a/src/llmq/quorums_debug.cpp b/src/llmq/quorums_debug.cpp index dba8963e946c2..13be503d0bc45 100644 --- a/src/llmq/quorums_debug.cpp +++ b/src/llmq/quorums_debug.cpp @@ -5,6 +5,7 @@ #include "quorums_debug.h" #include "chainparams.h" +#include "validation.h" #include "evo/deterministicmns.h" #include "quorums_utils.h" @@ -23,7 +24,17 @@ UniValue CDKGDebugSessionStatus::ToJson(int detailLevel) const std::vector dmnMembers; if (detailLevel == 2) { - dmnMembers = CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType) llmqType, quorumHash); + const CBlockIndex* pindex = nullptr; + { + LOCK(cs_main); + auto it = mapBlockIndex.find(quorumHash); + if (it != mapBlockIndex.end()) { + pindex = it->second; + } + } + if (pindex != nullptr) { + dmnMembers = CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType) llmqType, pindex); + } } ret.push_back(Pair("llmqType", llmqType)); diff --git a/src/llmq/quorums_dkgsession.cpp b/src/llmq/quorums_dkgsession.cpp index 1cfd343d3ff5e..d41633ecfc597 100644 --- a/src/llmq/quorums_dkgsession.cpp +++ b/src/llmq/quorums_dkgsession.cpp @@ -60,7 +60,7 @@ static bool ShouldSimulateError(const std::string& type) } CDKGLogger::CDKGLogger(const CDKGSession& _quorumDkg, const std::string& _func) : - CDKGLogger(_quorumDkg.params.type, _quorumDkg.quorumHash, _quorumDkg.height, _quorumDkg.AreWeMember(), _func) + CDKGLogger(_quorumDkg.params.type, _quorumDkg.pindexQuorum->GetBlockHash(), _quorumDkg.pindexQuorum->nHeight, _quorumDkg.AreWeMember(), _func) { } @@ -88,14 +88,13 @@ CDKGMember::CDKGMember(CDeterministicMNCPtr _dmn, size_t _idx) : } -bool CDKGSession::Init(int _height, const uint256& _quorumHash, const std::vector& mns, const uint256& _myProTxHash) +bool CDKGSession::Init(const CBlockIndex* _pindexQuorum, const std::vector& mns, const uint256& _myProTxHash) { if (mns.size() < params.minSize) { return false; } - height = _height; - quorumHash = _quorumHash; + pindexQuorum = _pindexQuorum; members.resize(mns.size()); memberIds.resize(members.size()); @@ -121,7 +120,7 @@ bool CDKGSession::Init(int _height, const uint256& _quorumHash, const std::vecto } if (!myProTxHash.IsNull()) { - quorumDKGDebugManager->InitLocalSessionStatus(params.type, quorumHash, height); + quorumDKGDebugManager->InitLocalSessionStatus(params.type, pindexQuorum->GetBlockHash(), pindexQuorum->nHeight); } CDKGLogger logger(*this, __func__); @@ -170,7 +169,7 @@ void CDKGSession::SendContributions(CDKGPendingMessages& pendingMessages) CDKGContribution qc; qc.llmqType = (uint8_t)params.type; - qc.quorumHash = quorumHash; + qc.quorumHash = pindexQuorum->GetBlockHash(); qc.proTxHash = myProTxHash; qc.vvec = vvecContribution; @@ -216,7 +215,7 @@ bool CDKGSession::PreVerifyMessage(const uint256& hash, const CDKGContribution& retBan = false; - if (qc.quorumHash != quorumHash) { + if (qc.quorumHash != pindexQuorum->GetBlockHash()) { logger.Batch("contribution for wrong quorum, rejecting"); return false; } @@ -316,7 +315,7 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGContribution& qc return; } - dkgManager.WriteVerifiedVvecContribution(params.type, qc.quorumHash, qc.proTxHash, qc.vvec); + dkgManager.WriteVerifiedVvecContribution(params.type, pindexQuorum, qc.proTxHash, qc.vvec); bool complain = false; CBLSSecretKey skContribution; @@ -398,7 +397,7 @@ void CDKGSession::VerifyPendingContributions() }); } else { size_t memberIdx = memberIndexes[i]; - dkgManager.WriteVerifiedSkContribution(params.type, quorumHash, members[memberIdx]->dmn->proTxHash, skContributions[i]); + dkgManager.WriteVerifiedSkContribution(params.type, pindexQuorum, members[memberIdx]->dmn->proTxHash, skContributions[i]); } } @@ -449,7 +448,7 @@ void CDKGSession::SendComplaint(CDKGPendingMessages& pendingMessages) CDKGComplaint qc(params); qc.llmqType = (uint8_t)params.type; - qc.quorumHash = quorumHash; + qc.quorumHash = pindexQuorum->GetBlockHash(); qc.proTxHash = myProTxHash; int badCount = 0; @@ -490,7 +489,7 @@ bool CDKGSession::PreVerifyMessage(const uint256& hash, const CDKGComplaint& qc, retBan = false; - if (qc.quorumHash != quorumHash) { + if (qc.quorumHash != pindexQuorum->GetBlockHash()) { logger.Batch("complaint for wrong quorum, rejecting"); return false; } @@ -643,7 +642,7 @@ void CDKGSession::SendJustification(CDKGPendingMessages& pendingMessages, const CDKGJustification qj; qj.llmqType = (uint8_t)params.type; - qj.quorumHash = quorumHash; + qj.quorumHash = pindexQuorum->GetBlockHash(); qj.proTxHash = myProTxHash; qj.contributions.reserve(forMembers.size()); @@ -688,7 +687,7 @@ bool CDKGSession::PreVerifyMessage(const uint256& hash, const CDKGJustification& retBan = false; - if (qj.quorumHash != quorumHash) { + if (qj.quorumHash != pindexQuorum->GetBlockHash()) { logger.Batch("justification for wrong quorum, rejecting"); return false; } @@ -824,7 +823,7 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGJustification& q receivedSkContributions[member->idx] = skContribution; member->weComplain = false; - dkgManager.WriteVerifiedSkContribution(params.type, quorumHash, member->dmn->proTxHash, skContribution); + dkgManager.WriteVerifiedSkContribution(params.type, pindexQuorum, member->dmn->proTxHash, skContribution); } member->complaintsFromOthers.erase(member2->dmn->proTxHash); } @@ -899,7 +898,7 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages) CDKGPrematureCommitment qc(params); qc.llmqType = (uint8_t)params.type; - qc.quorumHash = quorumHash; + qc.quorumHash = pindexQuorum->GetBlockHash(); qc.proTxHash = myProTxHash; for (size_t i = 0; i < members.size(); i++) { @@ -925,7 +924,7 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages) std::vector memberIndexes; std::vector vvecs; BLSSecretKeyVector skContributions; - if (!dkgManager.GetVerifiedContributions(params.type, quorumHash, qc.validMembers, memberIndexes, vvecs, skContributions)) { + if (!dkgManager.GetVerifiedContributions(params.type, pindexQuorum, qc.validMembers, memberIndexes, vvecs, skContributions)) { logger.Batch("failed to get valid contributions"); return; } @@ -1012,7 +1011,7 @@ bool CDKGSession::PreVerifyMessage(const uint256& hash, const CDKGPrematureCommi retBan = false; - if (qc.quorumHash != quorumHash) { + if (qc.quorumHash != pindexQuorum->GetBlockHash()) { logger.Batch("commitment for wrong quorum, rejecting"); return false; } @@ -1091,7 +1090,7 @@ void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGPrematureCommitm std::vector vvecs; BLSSecretKeyVector skContributions; BLSVerificationVectorPtr quorumVvec; - if (dkgManager.GetVerifiedContributions(params.type, qc.quorumHash, qc.validMembers, memberIndexes, vvecs, skContributions)) { + if (dkgManager.GetVerifiedContributions(params.type, pindexQuorum, qc.validMembers, memberIndexes, vvecs, skContributions)) { quorumVvec = cache.BuildQuorumVerificationVector(::SerializeHash(memberIndexes), vvecs); } diff --git a/src/llmq/quorums_dkgsession.h b/src/llmq/quorums_dkgsession.h index e6a23a5f6bb52..38e96dc654917 100644 --- a/src/llmq/quorums_dkgsession.h +++ b/src/llmq/quorums_dkgsession.h @@ -249,8 +249,7 @@ class CDKGSession CBLSWorkerCache cache; CDKGSessionManager& dkgManager; - uint256 quorumHash; - int height{-1}; + const CBlockIndex* pindexQuorum; private: std::vector> members; @@ -287,7 +286,7 @@ class CDKGSession CDKGSession(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) : params(_params), blsWorker(_blsWorker), cache(_blsWorker), dkgManager(_dkgManager) {} - bool Init(int _height, const uint256& _quorumHash, const std::vector& mns, const uint256& _myProTxHash); + bool Init(const CBlockIndex* pindexQuorum, const std::vector& mns, const uint256& _myProTxHash); size_t GetMyMemberIndex() const { return myIdx; } diff --git a/src/llmq/quorums_dkgsessionhandler.cpp b/src/llmq/quorums_dkgsessionhandler.cpp index 938b2fe7d08cc..e20bf952ac5a1 100644 --- a/src/llmq/quorums_dkgsessionhandler.cpp +++ b/src/llmq/quorums_dkgsessionhandler.cpp @@ -139,7 +139,7 @@ void CDKGSessionHandler::ProcessMessage(CNode* pfrom, const std::string& strComm } } -bool CDKGSessionHandler::InitNewQuorum(int newQuorumHeight, const uint256& newQuorumHash) +bool CDKGSessionHandler::InitNewQuorum(const CBlockIndex* pindexQuorum) { //AssertLockHeld(cs_main); @@ -147,13 +147,13 @@ bool CDKGSessionHandler::InitNewQuorum(int newQuorumHeight, const uint256& newQu curSession = std::make_shared(params, blsWorker, dkgManager); - if (!deterministicMNManager->IsDIP3Enforced(newQuorumHeight)) { + if (!deterministicMNManager->IsDIP3Enforced(pindexQuorum->nHeight)) { return false; } - auto mns = CLLMQUtils::GetAllQuorumMembers(params.type, newQuorumHash); + auto mns = CLLMQUtils::GetAllQuorumMembers(params.type, pindexQuorum); - if (!curSession->Init(newQuorumHeight, newQuorumHash, mns, activeMasternodeInfo.proTxHash)) { + if (!curSession->Init(pindexQuorum, mns, activeMasternodeInfo.proTxHash)) { LogPrintf("CDKGSessionManager::%s -- quorum initialiation failed\n", __func__); return false; } @@ -455,7 +455,13 @@ void CDKGSessionHandler::HandleDKGRound() curQuorumHeight = quorumHeight; } - if (!InitNewQuorum(curQuorumHeight, curQuorumHash)) { + const CBlockIndex* pindexQuorum; + { + LOCK(cs_main); + pindexQuorum = mapBlockIndex.at(curQuorumHash); + } + + if (!InitNewQuorum(pindexQuorum)) { // should actually never happen WaitForNewQuorum(curQuorumHash); throw AbortPhaseException(); @@ -470,16 +476,16 @@ void CDKGSessionHandler::HandleDKGRound() if (curSession->AreWeMember() || GetBoolArg("-watchquorums", DEFAULT_WATCH_QUORUMS)) { std::set connections; if (curSession->AreWeMember()) { - connections = CLLMQUtils::GetQuorumConnections(params.type, curQuorumHash, curSession->myProTxHash); + connections = CLLMQUtils::GetQuorumConnections(params.type, pindexQuorum, curSession->myProTxHash); } else { - auto cindexes = CLLMQUtils::CalcDeterministicWatchConnections(params.type, curQuorumHash, curSession->members.size(), 1); + auto cindexes = CLLMQUtils::CalcDeterministicWatchConnections(params.type, pindexQuorum, curSession->members.size(), 1); for (auto idx : cindexes) { connections.emplace(curSession->members[idx]->dmn->proTxHash); } } if (!connections.empty()) { if (LogAcceptCategory("llmq-dkg")) { - std::string debugMsg = strprintf("CDKGSessionManager::%s -- adding masternodes quorum connections for quorum %s:\n", __func__, curSession->quorumHash.ToString()); + std::string debugMsg = strprintf("CDKGSessionManager::%s -- adding masternodes quorum connections for quorum %s:\n", __func__, curSession->pindexQuorum->GetBlockHash().ToString()); auto mnList = deterministicMNManager->GetListAtChainTip(); for (const auto& c : connections) { auto dmn = mnList.GetValidMN(c); diff --git a/src/llmq/quorums_dkgsessionhandler.h b/src/llmq/quorums_dkgsessionhandler.h index c297057e9c2ab..6613d06b324e2 100644 --- a/src/llmq/quorums_dkgsessionhandler.h +++ b/src/llmq/quorums_dkgsessionhandler.h @@ -125,7 +125,7 @@ class CDKGSessionHandler void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); private: - bool InitNewQuorum(int newQuorumHeight, const uint256& newQuorumHash); + bool InitNewQuorum(const CBlockIndex* pindexQuorum); std::pair GetPhaseAndQuorumHash() const; diff --git a/src/llmq/quorums_dkgsessionmgr.cpp b/src/llmq/quorums_dkgsessionmgr.cpp index c68d95d00ad8d..b42de05f29484 100644 --- a/src/llmq/quorums_dkgsessionmgr.cpp +++ b/src/llmq/quorums_dkgsessionmgr.cpp @@ -198,19 +198,19 @@ bool CDKGSessionManager::GetPrematureCommitment(const uint256& hash, CDKGPrematu return false; } -void CDKGSessionManager::WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec) +void CDKGSessionManager::WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec) { - llmqDb.Write(std::make_tuple(DB_VVEC, (uint8_t)llmqType, quorumHash, proTxHash), *vvec); + llmqDb.Write(std::make_tuple(DB_VVEC, (uint8_t) llmqType, pindexQuorum->GetBlockHash(), proTxHash), *vvec); } -void CDKGSessionManager::WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& proTxHash, const CBLSSecretKey& skContribution) +void CDKGSessionManager::WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, const CBLSSecretKey& skContribution) { - llmqDb.Write(std::make_tuple(DB_SKCONTRIB, (uint8_t)llmqType, quorumHash, proTxHash), skContribution); + llmqDb.Write(std::make_tuple(DB_SKCONTRIB, (uint8_t) llmqType, pindexQuorum->GetBlockHash(), proTxHash), skContribution); } -bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, BLSSecretKeyVector& skContributionsRet) +bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, BLSSecretKeyVector& skContributionsRet) { - auto members = CLLMQUtils::GetAllQuorumMembers(llmqType, quorumHash); + auto members = CLLMQUtils::GetAllQuorumMembers(llmqType, pindexQuorum); memberIndexesRet.clear(); vvecsRet.clear(); @@ -222,7 +222,7 @@ bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, if (validMembers[i]) { BLSVerificationVectorPtr vvec; CBLSSecretKey skContribution; - if (!GetVerifiedContribution(llmqType, quorumHash, members[i]->proTxHash, vvec, skContribution)) { + if (!GetVerifiedContribution(llmqType, pindexQuorum, members[i]->proTxHash, vvec, skContribution)) { return false; } @@ -234,10 +234,10 @@ bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, return true; } -bool CDKGSessionManager::GetVerifiedContribution(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& proTxHash, BLSVerificationVectorPtr& vvecRet, CBLSSecretKey& skContributionRet) +bool CDKGSessionManager::GetVerifiedContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, BLSVerificationVectorPtr& vvecRet, CBLSSecretKey& skContributionRet) { LOCK(contributionsCacheCs); - ContributionsCacheKey cacheKey = {llmqType, quorumHash, proTxHash}; + ContributionsCacheKey cacheKey = {llmqType, pindexQuorum->GetBlockHash(), proTxHash}; auto it = contributionsCache.find(cacheKey); if (it != contributionsCache.end()) { vvecRet = it->second.vvec; @@ -248,10 +248,10 @@ bool CDKGSessionManager::GetVerifiedContribution(Consensus::LLMQType llmqType, c BLSVerificationVector vvec; BLSVerificationVectorPtr vvecPtr; CBLSSecretKey skContribution; - if (llmqDb.Read(std::make_tuple(DB_VVEC, (uint8_t)llmqType, quorumHash, proTxHash), vvec)) { + if (llmqDb.Read(std::make_tuple(DB_VVEC, (uint8_t) llmqType, pindexQuorum->GetBlockHash(), proTxHash), vvec)) { vvecPtr = std::make_shared(std::move(vvec)); } - llmqDb.Read(std::make_tuple(DB_SKCONTRIB, (uint8_t)llmqType, quorumHash, proTxHash), skContribution); + llmqDb.Read(std::make_tuple(DB_SKCONTRIB, (uint8_t) llmqType, pindexQuorum->GetBlockHash(), proTxHash), skContribution); it = contributionsCache.emplace(cacheKey, ContributionsCacheEntry{GetTimeMillis(), vvecPtr, skContribution}).first; diff --git a/src/llmq/quorums_dkgsessionmgr.h b/src/llmq/quorums_dkgsessionmgr.h index cfb9850ec0e61..721f189782f41 100644 --- a/src/llmq/quorums_dkgsessionmgr.h +++ b/src/llmq/quorums_dkgsessionmgr.h @@ -63,10 +63,10 @@ class CDKGSessionManager bool GetPrematureCommitment(const uint256& hash, CDKGPrematureCommitment& ret) const; // Verified contributions are written while in the DKG - void WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec); - void WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& proTxHash, const CBLSSecretKey& skContribution); - bool GetVerifiedContributions(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, BLSSecretKeyVector& skContributionsRet); - bool GetVerifiedContribution(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& proTxHash, BLSVerificationVectorPtr& vvecRet, CBLSSecretKey& skContributionRet); + void WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec); + void WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, const CBLSSecretKey& skContribution); + bool GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, BLSSecretKeyVector& skContributionsRet); + bool GetVerifiedContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, BLSVerificationVectorPtr& vvecRet, CBLSSecretKey& skContributionRet); private: void CleanupCache(); diff --git a/src/llmq/quorums_utils.cpp b/src/llmq/quorums_utils.cpp index 338b01bf54c78..3af8aa85371a1 100644 --- a/src/llmq/quorums_utils.cpp +++ b/src/llmq/quorums_utils.cpp @@ -12,11 +12,11 @@ namespace llmq { -std::vector CLLMQUtils::GetAllQuorumMembers(Consensus::LLMQType llmqType, const uint256& blockHash) +std::vector CLLMQUtils::GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum) { auto& params = Params().GetConsensus().llmqs.at(llmqType); - auto allMns = deterministicMNManager->GetListForBlock(blockHash); - auto modifier = ::SerializeHash(std::make_pair((uint8_t)llmqType, blockHash)); + auto allMns = deterministicMNManager->GetListForBlock(pindexQuorum); + auto modifier = ::SerializeHash(std::make_pair((uint8_t) llmqType, pindexQuorum->GetBlockHash())); return allMns.CalculateQuorum(params.size, modifier); } @@ -41,11 +41,11 @@ uint256 CLLMQUtils::BuildSignHash(Consensus::LLMQType llmqType, const uint256& q return h.GetHash(); } -std::set CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, const uint256& blockHash, const uint256& forMember) +std::set CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& forMember) { auto& params = Params().GetConsensus().llmqs.at(llmqType); - auto mns = GetAllQuorumMembers(llmqType, blockHash); + auto mns = GetAllQuorumMembers(llmqType, pindexQuorum); std::set result; for (size_t i = 0; i < mns.size(); i++) { auto& dmn = mns[i]; @@ -73,7 +73,7 @@ std::set CLLMQUtils::GetQuorumConnections(Consensus::LLMQType llmqType, return result; } -std::set CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const uint256& blockHash, size_t memberCount, size_t connectionCount) +std::set CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, size_t memberCount, size_t connectionCount) { static uint256 qwatchConnectionSeed; static std::atomic qwatchConnectionSeedGenerated{false}; @@ -89,7 +89,7 @@ std::set CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQTy std::set result; uint256 rnd = qwatchConnectionSeed; for (size_t i = 0; i < connectionCount; i++) { - rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair((uint8_t)llmqType, blockHash))); + rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair((uint8_t) llmqType, pindexQuorum->GetBlockHash()))); result.emplace(rnd.GetUint64(0) % memberCount); } return result; diff --git a/src/llmq/quorums_utils.h b/src/llmq/quorums_utils.h index a8c5ba7924bbf..6b1c3db07847d 100644 --- a/src/llmq/quorums_utils.h +++ b/src/llmq/quorums_utils.h @@ -19,7 +19,7 @@ class CLLMQUtils { public: // includes members which failed DKG - static std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const uint256& blockHash); + static std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum); static uint256 BuildCommitmentHash(uint8_t llmqType, const uint256& blockHash, const std::vector& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash); static uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash); @@ -31,8 +31,8 @@ class CLLMQUtils return BuildSignHash((Consensus::LLMQType)s.llmqType, s.quorumHash, s.id, s.msgHash); } - static std::set GetQuorumConnections(Consensus::LLMQType llmqType, const uint256& blockHash, const uint256& forMember); - static std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const uint256& blockHash, size_t memberCount, size_t connectionCount); + static std::set GetQuorumConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& forMember); + static std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, size_t memberCount, size_t connectionCount); static bool IsQuorumActive(Consensus::LLMQType llmqType, const uint256& quorumHash); diff --git a/src/masternode-meta.cpp b/src/masternode-meta.cpp index 18f07f1beb9d6..9ec37b9e247fa 100644 --- a/src/masternode-meta.cpp +++ b/src/masternode-meta.cpp @@ -118,7 +118,6 @@ std::string CMasternodeMetaMan::ToString() const std::ostringstream info; info << "Masternodes: meta infos object count: " << (int)metaInfos.size() << - ", deterministic masternode count: " << deterministicMNManager->GetListAtChainTip().GetAllMNsCount() << ", nDsqCount: " << (int)nDsqCount; return info.str(); } diff --git a/src/masternode-meta.h b/src/masternode-meta.h index 8ef5c753fe6ba..fe4104611d448 100644 --- a/src/masternode-meta.h +++ b/src/masternode-meta.h @@ -100,7 +100,11 @@ class CMasternodeMetaMan std::string strVersion; if(ser_action.ForRead()) { + Clear(); READWRITE(strVersion); + if (strVersion != SERIALIZATION_VERSION_STRING) { + return; + } } else { strVersion = SERIALIZATION_VERSION_STRING; @@ -122,10 +126,6 @@ class CMasternodeMetaMan } READWRITE(nDsqCount); - - if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { - Clear(); - } } public: diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index d71b15df7cacd..6e4ede3e41361 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -271,7 +271,7 @@ std::map GetRequiredPaymentsStrings(int nStartHeight, int nEnd bool doProjection = false; for(int h = nStartHeight; h < nEndHeight; h++) { if (h <= nChainTipHeight) { - auto payee = deterministicMNManager->GetListForBlock(chainActive[h - 1]->GetBlockHash()).GetMNPayee(); + auto payee = deterministicMNManager->GetListForBlock(chainActive[h - 1]).GetMNPayee(); mapPayments.emplace(h, GetRequiredPaymentsString(h, payee)); } else { doProjection = true; @@ -323,13 +323,13 @@ bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward, CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward); - uint256 blockHash; + const CBlockIndex* pindex; { LOCK(cs_main); - blockHash = chainActive[nBlockHeight - 1]->GetBlockHash(); + pindex = chainActive[nBlockHeight - 1]; } uint256 proTxHash; - auto dmnPayee = deterministicMNManager->GetListForBlock(blockHash).GetMNPayee(); + auto dmnPayee = deterministicMNManager->GetListForBlock(pindex).GetMNPayee(); if (!dmnPayee) { return false; } diff --git a/src/rpc/rpcevo.cpp b/src/rpc/rpcevo.cpp index 4c5ed8468770d..35913e245e16b 100644 --- a/src/rpc/rpcevo.cpp +++ b/src/rpc/rpcevo.cpp @@ -972,7 +972,7 @@ UniValue protx_list(const JSONRPCRequest& request) setOutpts.emplace(outpt); } - CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(chainActive[height]->GetBlockHash()); + CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(chainActive[height]); mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) { if (setOutpts.count(dmn->collateralOutpoint) || CheckWalletOwnsKey(pwallet, dmn->pdmnState->keyIDOwner) || @@ -997,7 +997,7 @@ UniValue protx_list(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid height specified"); } - CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(chainActive[height]->GetBlockHash()); + CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(chainActive[height]); bool onlyValid = type == "valid"; mnList.ForEachMN(onlyValid, [&](const CDeterministicMNCPtr& dmn) { ret.push_back(BuildDMNListEntry(pwallet, dmn, detailed)); diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index b9709ef8c9020..78ae2bb837576 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -80,7 +80,7 @@ UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMembers, b { UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("height", quorum->height)); + ret.push_back(Pair("height", quorum->pindexQuorum->nHeight)); ret.push_back(Pair("type", quorum->params.name)); ret.push_back(Pair("quorumHash", quorum->qc.quorumHash.ToString())); ret.push_back(Pair("minedBlock", quorum->minedBlockHash.ToString())); @@ -222,7 +222,7 @@ UniValue quorum_memberof(const JSONRPCRequest& request) pindexTip = chainActive.Tip(); } - auto mnList = deterministicMNManager->GetListForBlock(pindexTip->GetBlockHash()); + auto mnList = deterministicMNManager->GetListForBlock(pindexTip); auto dmn = mnList.GetMN(protxHash); if (!dmn) { throw JSONRPCError(RPC_INVALID_PARAMETER, "masternode not found"); diff --git a/src/script/script.h b/src/script/script.h index 74cbb2bf136f2..d0a7845048d28 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -645,6 +645,15 @@ class CScript : public CScriptBase // The default std::vector::clear() does not release memory. CScriptBase().swap(*this); } + + template + void Serialize(Stream& s) const { + s << *(CScriptBase*)this; + } + template + void Unserialize(Stream& s) { + s >> *(CScriptBase*)this; + } }; class CReserveScript diff --git a/src/spentindex.h b/src/spentindex.h index a3d84e86d0c38..c79a007a0bb46 100644 --- a/src/spentindex.h +++ b/src/spentindex.h @@ -210,7 +210,7 @@ struct CAddressUnspentValue { template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(satoshis); - READWRITE(*(CScriptBase*)(&script)); + READWRITE(script); READWRITE(blockHeight); } From a198a04e04301ac967a2765d8149ea678d15e6ec Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 22 May 2019 08:35:51 +0200 Subject: [PATCH 12/19] Show number of InstantSend locks in Debug Console (#2919) * Implement GetInstantSendLockCount in CInstantSendManager * Add islockCountChanged signal to client model * Show number of InstantSend locks in debug console --- src/llmq/quorums_instantsend.cpp | 27 +++++++++++++++++++++++++++ src/llmq/quorums_instantsend.h | 3 +++ src/qt/clientmodel.cpp | 11 +++++++++++ src/qt/clientmodel.h | 3 +++ src/qt/forms/debugwindow.ui | 14 ++++++++++++++ src/qt/rpcconsole.cpp | 6 ++++++ src/qt/rpcconsole.h | 2 ++ 7 files changed, 66 insertions(+) diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index fc2c7dd5f6335..8891197b6d23c 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -185,6 +185,28 @@ bool CInstantSendDb::HasArchivedInstantSendLock(const uint256& islockHash) return db.Exists(std::make_tuple(std::string("is_a2"), islockHash)); } +size_t CInstantSendDb::GetInstantSendLockCount() +{ + auto it = std::unique_ptr(db.NewIterator()); + auto firstKey = std::make_tuple(std::string("is_i"), uint256()); + + it->Seek(firstKey); + + size_t cnt = 0; + while (it->Valid()) { + decltype(firstKey) curKey; + if (!it->GetKey(curKey) || std::get<0>(curKey) != "is_i") { + break; + } + + cnt++; + + it->Next(); + } + + return cnt; +} + CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash) { CInstantSendLockPtr ret; @@ -1412,6 +1434,11 @@ CInstantSendLockPtr CInstantSendManager::GetConflictingLock(const CTransaction& return nullptr; } +size_t CInstantSendManager::GetInstantSendLockCount() +{ + return db.GetInstantSendLockCount(); +} + void CInstantSendManager::WorkThreadMain() { while (!workInterrupt) { diff --git a/src/llmq/quorums_instantsend.h b/src/llmq/quorums_instantsend.h index 955b1322355dd..456ba44bb707c 100644 --- a/src/llmq/quorums_instantsend.h +++ b/src/llmq/quorums_instantsend.h @@ -62,6 +62,7 @@ class CInstantSendDb std::unordered_map RemoveConfirmedInstantSendLocks(int nUntilHeight); void RemoveArchivedInstantSendLocks(int nUntilHeight); bool HasArchivedInstantSendLock(const uint256& islockHash); + size_t GetInstantSendLockCount(); CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash); uint256 GetInstantSendLockHashByTxid(const uint256& txid); @@ -159,6 +160,8 @@ class CInstantSendManager : public CRecoveredSigsListener bool AlreadyHave(const CInv& inv); bool GetInstantSendLockByHash(const uint256& hash, CInstantSendLock& ret); + size_t GetInstantSendLockCount(); + void WorkThreadMain(); }; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 2b26ee9c00747..0e7bfcf23579b 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -23,6 +23,8 @@ #include "masternode-sync.h" #include "privatesend.h" +#include "llmq/quorums_instantsend.h" + #include #include @@ -161,6 +163,14 @@ size_t ClientModel::getMempoolDynamicUsage() const return mempool.DynamicMemoryUsage(); } +size_t ClientModel::getInstantSentLockCount() const +{ + if (!llmq::quorumInstantSendManager) { + return 0; + } + return llmq::quorumInstantSendManager->GetInstantSendLockCount(); +} + double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const { CBlockIndex *tip = const_cast(tipIn); @@ -177,6 +187,7 @@ void ClientModel::updateTimer() // no locking required at this point // the following calls will acquire the required lock Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage()); + Q_EMIT islockCountChanged(getInstantSentLockCount()); Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index d3b429f0b4a08..846a71d46a85a 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -63,6 +63,8 @@ class ClientModel : public QObject long getMempoolSize() const; //! Return the dynamic memory usage of the mempool size_t getMempoolDynamicUsage() const; + //! Return number of ISLOCKs + size_t getInstantSentLockCount() const; void setMasternodeList(const CDeterministicMNList& mnList); CDeterministicMNList getMasternodeList() const; @@ -117,6 +119,7 @@ class ClientModel : public QObject void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header); void additionalDataSyncProgressChanged(double nSyncProgress); void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); + void islockCountChanged(size_t count); void networkActiveChanged(bool networkActive); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index cd60a440aae51..ad14df1bd330c 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -408,6 +408,20 @@ + + + + InstantSend locks + + + + + + + N/A + + + diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 01f5c4aeecf08..cb1a80c129402 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -563,6 +563,7 @@ void RPCConsole::setClientModel(ClientModel *model) connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64))); connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t))); + connect(model, SIGNAL(islockCountChanged(size_t)), this, SLOT(setInstantSendLockCount(size_t))); // set up peer table ui->peerWidget->setModel(model->getPeerTableModel()); @@ -906,6 +907,11 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB"); } +void RPCConsole::setInstantSendLockCount(size_t count) +{ + ui->instantSendLockCount->setText(QString::number(count)); +} + void RPCConsole::on_lineEdit_returnPressed() { QString cmd = ui->lineEdit->text(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 8f195cde5a77a..c1466cf44fc6b 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -111,6 +111,8 @@ public Q_SLOTS: void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers); /** Set size (number of transactions and memory usage) of the mempool in the UI */ void setMempoolSize(long numberOfTxs, size_t dynUsage); + /** Set number of InstantSend locks */ + void setInstantSendLockCount(size_t count); /** Go forward or back in history */ void browseHistory(int offset); /** Scroll console view to end */ From a8fb8252e98c49ddfc04aaf56197da136f12bd76 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 7 Aug 2019 16:07:22 +0200 Subject: [PATCH 13/19] Use fEnablePrivateSend instead of fPrivateSendRunning Required due missing refactorings. --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 9ca1bd27157df..5260e47241037 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -960,7 +960,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer // Disabling macOS App Nap on initial sync, disk, reindex operations and mixing. bool disableAppNap = !masternodeSync.IsSynced(); #ifdef ENABLE_WALLET - disableAppNap |= privateSendClient.fPrivateSendRunning; + disableAppNap |= privateSendClient.fEnablePrivateSend; #endif // ENABLE_WALLET if (disableAppNap) { m_app_nap_inhibitor->disableAppNap(); From 2e0cf8a30b83fde7f0d195dafd7b77c24fda13d2 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 7 Aug 2019 17:49:44 +0200 Subject: [PATCH 14/19] Add "instantsendlocks" to getmempoolinfo RPC (#3047) --- src/rpc/blockchain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d08d518108fcf..4edbd353aa1cd 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1503,6 +1503,7 @@ UniValue mempoolInfoToJSON() size_t maxmempool = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; ret.push_back(Pair("maxmempool", (int64_t) maxmempool)); ret.push_back(Pair("mempoolminfee", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK()))); + ret.push_back(Pair("instantsendlocks", (int64_t)llmq::quorumInstantSendManager->GetInstantSendLockCount())); return ret; } @@ -1520,6 +1521,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request) " \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n" " \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n" " \"mempoolminfee\": xxxxx (numeric) Minimum fee for tx to be accepted\n" + " \"instantsendlocks\": xxxxx, (numeric) Number of unconfirmed instant send locks\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmempoolinfo", "") From 8c49d9b54509e16ef5caeca2c904c4fb4169be16 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 12 Aug 2019 09:35:44 +0200 Subject: [PATCH 15/19] Remove recovered sigs from the LLMQ db when corresponding IS locks get confirmed (#3048) * Remove unused overload of RemoveInstantSendLock * Move deletion of recovered sigs into own method * Remove recovered sigs for fully confirmed IS locks * Also remove rs_t entries when removing recovered sigs from the outside CleanupOldRecoveredSigs already does this as the last step, but when RemoveRecoveredSig is called from the outside (e.g. from InstantSend), these keys are not removed. This PR fixes this by storing the write time into rs_r and later uses it to remove the rs_t entry. Old entries will be incompatible with this (1 byte written in the past, 4 bytes written now). This checked by comparing the data size with sizeof(uint32_t). * Add TODO --- src/llmq/quorums_instantsend.cpp | 16 ++++--- src/llmq/quorums_instantsend.h | 1 - src/llmq/quorums_signing.cpp | 76 +++++++++++++++++++++++--------- src/llmq/quorums_signing.h | 6 +++ 4 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index 8891197b6d23c..2d616df5f579b 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -61,13 +61,6 @@ void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const CInstant } } -void CInstantSendDb::RemoveInstantSendLock(const uint256& hash, CInstantSendLockPtr islock) -{ - CDBBatch batch(db); - RemoveInstantSendLock(batch, hash, islock); - db.WriteBatch(batch); -} - void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock) { if (!islock) { @@ -1106,6 +1099,8 @@ void CInstantSendManager::UpdatedBlockTip(const CBlockIndex* pindexNew) void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex) { + auto& consensusParams = Params().GetConsensus(); + std::unordered_map removeISLocks; { LOCK(cs); @@ -1123,7 +1118,14 @@ void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex) for (auto& in : islock->inputs) { auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in)); inputRequestIds.erase(inputRequestId); + + // no need to keep recovered sigs for fully confirmed IS locks, as there is no chance for conflicts + // from now on. All inputs are spent now and can't be spend in any other TX. + quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, inputRequestId); } + + // same as in the loop + quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, islock->GetRequestId()); } // Find all previously unlocked TXs that got locked by this fully confirmed (ChainLock) block and remove them diff --git a/src/llmq/quorums_instantsend.h b/src/llmq/quorums_instantsend.h index 456ba44bb707c..2c5fdb88fba2d 100644 --- a/src/llmq/quorums_instantsend.h +++ b/src/llmq/quorums_instantsend.h @@ -53,7 +53,6 @@ class CInstantSendDb CInstantSendDb(CDBWrapper& _db) : db(_db) {} void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock); - void RemoveInstantSendLock(const uint256& hash, CInstantSendLockPtr islock); void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock); void WriteInstantSendLockMined(const uint256& hash, int nHeight); diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index ce14a8e460159..d5b9a79b2dbdf 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -224,12 +224,15 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig) { CDBBatch batch(db); + uint32_t curTime = GetAdjustedTime(); + // we put these close to each other to leverage leveldb's key compaction // this way, the second key can be used for fast HasRecoveredSig checks while the first key stores the recSig auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id); auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash); batch.Write(k1, recSig); - batch.Write(k2, (uint8_t)1); + // this key is also used to store the current time, so that we can easily get to the "rs_t" key when we have the id + batch.Write(k2, curTime); // store by object hash auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash()); @@ -241,7 +244,7 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig) batch.Write(k4, (uint8_t)1); // store by current time. Allows fast cleanup of old recSigs - auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32(GetAdjustedTime()), recSig.llmqType, recSig.id); + auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32(curTime), recSig.llmqType, recSig.id); batch.Write(k5, (uint8_t)1); db.WriteBatch(batch); @@ -256,6 +259,50 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig) } } +void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey) +{ + AssertLockHeld(cs); + + CRecoveredSig recSig; + if (!ReadRecoveredSig(llmqType, id, recSig)) { + return; + } + + auto signHash = CLLMQUtils::BuildSignHash(recSig); + + auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id); + auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash); + auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash()); + auto k4 = std::make_tuple(std::string("rs_s"), signHash); + batch.Erase(k1); + batch.Erase(k2); + batch.Erase(k3); + batch.Erase(k4); + + if (deleteTimeKey) { + CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION); + // TODO remove the size() == sizeof(uint32_t) in a future version (when we stop supporting upgrades from < 0.14.1) + if (db.ReadDataStream(k2, writeTimeDs) && writeTimeDs.size() == sizeof(uint32_t)) { + uint32_t writeTime; + writeTimeDs >> writeTime; + auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t) htobe32(writeTime), recSig.llmqType, recSig.id); + batch.Erase(k5); + } + } + + hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)); + hasSigForSessionCache.erase(signHash); + hasSigForHashCache.erase(recSig.GetHash()); +} + +void CRecoveredSigsDb::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) +{ + LOCK(cs); + CDBBatch batch(db); + RemoveRecoveredSig(batch, llmqType, id, true); + db.WriteBatch(batch); +} + void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) { std::unique_ptr pcursor(db.NewIterator()); @@ -292,25 +339,7 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) { LOCK(cs); for (auto& e : toDelete) { - CRecoveredSig recSig; - if (!ReadRecoveredSig(e.first, e.second, recSig)) { - continue; - } - - auto signHash = CLLMQUtils::BuildSignHash(recSig); - - auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id); - auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash); - auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash()); - auto k4 = std::make_tuple(std::string("rs_s"), signHash); - batch.Erase(k1); - batch.Erase(k2); - batch.Erase(k3); - batch.Erase(k4); - - hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)); - hasSigForSessionCache.erase(signHash); - hasSigForHashCache.erase(recSig.GetHash()); + RemoveRecoveredSig(batch, e.first, e.second, false); if (batch.SizeEstimate() >= (1 << 24)) { db.WriteBatch(batch); @@ -680,6 +709,11 @@ void CSigningManager::PushReconstructedRecoveredSig(const llmq::CRecoveredSig& r pendingReconstructedRecoveredSigs.emplace_back(recoveredSig, quorum); } +void CSigningManager::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) +{ + db.RemoveRecoveredSig(llmqType, id); +} + void CSigningManager::Cleanup() { int64_t now = GetTimeMillis(); diff --git a/src/llmq/quorums_signing.h b/src/llmq/quorums_signing.h index 1916a66e6a828..f6e3f3873328d 100644 --- a/src/llmq/quorums_signing.h +++ b/src/llmq/quorums_signing.h @@ -84,6 +84,7 @@ class CRecoveredSigsDb bool GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret); bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret); void WriteRecoveredSig(const CRecoveredSig& recSig); + void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); void CleanupOldRecoveredSigs(int64_t maxAge); @@ -96,6 +97,7 @@ class CRecoveredSigsDb private: bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret); + void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey); }; class CRecoveredSigsListener @@ -144,6 +146,10 @@ class CSigningManager // This is the case for example when a signature appears as part of InstantSend or ChainLocks void PushReconstructedRecoveredSig(const CRecoveredSig& recoveredSig, const CQuorumCPtr& quorum); + // This is called when a recovered signature can be safely removed from the DB. This is only safe when some other + // mechanism prevents possible conflicts. As an example, ChainLocks prevent conflicts in confirmed TXs InstantSend votes + void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); + private: void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman); bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, bool& retBan); From 17ba23871c05fd21f4da0316434c319c49a74222 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 12 Aug 2019 09:36:09 +0200 Subject: [PATCH 16/19] Re-verify invalid IS sigs when the active quorum set rotated (#3052) * Split ProcessPendingInstantSendLocks into two methods * Split SelectQuorumForSigning into SelectQuorumForSigning and GetActiveQuorumSet * Implement retrying of IS lock verification when the LLMQ active set rotates --- src/llmq/quorums_instantsend.cpp | 51 ++++++++++++++++++++++++++++---- src/llmq/quorums_instantsend.h | 1 + src/llmq/quorums_signing.cpp | 11 +++++-- src/llmq/quorums_signing.h | 1 + 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index 2d616df5f579b..fecebdf71a0af 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -727,8 +727,6 @@ bool CInstantSendManager::PreVerifyInstantSendLock(NodeId nodeId, const llmq::CI bool CInstantSendManager::ProcessPendingInstantSendLocks() { - auto llmqType = Params().GetConsensus().llmqForInstantSend; - decltype(pendingInstantSendLocks) pend; { @@ -750,6 +748,44 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() tipHeight = chainActive.Height(); } + auto llmqType = Params().GetConsensus().llmqForInstantSend; + + // Every time a new quorum enters the active set, an older one is removed. This means that between two blocks, the + // active set can be different, leading to different selection of the signing quorum. When we detect such rotation + // of the active set, we must re-check invalid sigs against the previous active set and only ban nodes when this also + // fails. + auto quorums1 = quorumSigningManager->GetActiveQuorumSet(llmqType, tipHeight); + auto quorums2 = quorumSigningManager->GetActiveQuorumSet(llmqType, tipHeight - 1); + bool quorumsRotated = quorums1 != quorums2; + + if (quorumsRotated) { + // first check against the current active set and don't ban + auto badISLocks = ProcessPendingInstantSendLocks(tipHeight, pend, false); + if (!badISLocks.empty()) { + LogPrintf("CInstantSendManager::%s -- detected LLMQ active set rotation, redoing verification on old active set\n", __func__); + + // filter out valid IS locks from "pend" + for (auto it = pend.begin(); it != pend.end(); ) { + if (!badISLocks.count(it->first)) { + it = pend.erase(it); + } else { + ++it; + } + } + // now check against the previous active set and perform banning if this fails + ProcessPendingInstantSendLocks(tipHeight - 1, pend, true); + } + } else { + ProcessPendingInstantSendLocks(tipHeight, pend, true); + } + + return true; +} + +std::unordered_set CInstantSendManager::ProcessPendingInstantSendLocks(int signHeight, const std::unordered_map>& pend, bool ban) +{ + auto llmqType = Params().GetConsensus().llmqForInstantSend; + CBLSBatchVerifier batchVerifier(false, true, 8); std::unordered_map> recSigs; @@ -774,10 +810,10 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() continue; } - auto quorum = quorumSigningManager->SelectQuorumForSigning(llmqType, tipHeight, id); + auto quorum = quorumSigningManager->SelectQuorumForSigning(llmqType, signHeight, id); if (!quorum) { // should not happen, but if one fails to select, all others will also fail to select - return false; + return {}; } uint256 signHash = CLLMQUtils::BuildSignHash(llmqType, quorum->qc.quorumHash, id, islock.txid); batchVerifier.PushMessage(nodeId, hash, signHash, islock.sig.Get(), quorum->qc.quorumPublicKey); @@ -800,7 +836,9 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() batchVerifier.Verify(); - if (!batchVerifier.badSources.empty()) { + std::unordered_set badISLocks; + + if (ban && !batchVerifier.badSources.empty()) { LOCK(cs_main); for (auto& nodeId : batchVerifier.badSources) { // Let's not be too harsh, as the peer might simply be unlucky and might have sent us an old lock which @@ -816,6 +854,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() if (batchVerifier.badMessages.count(hash)) { LogPrintf("CInstantSendManager::%s -- txid=%s, islock=%s: invalid sig in islock, peer=%d\n", __func__, islock.txid.ToString(), hash.ToString(), nodeId); + badISLocks.emplace(hash); continue; } @@ -836,7 +875,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() } } - return true; + return badISLocks; } void CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& hash, const CInstantSendLock& islock) diff --git a/src/llmq/quorums_instantsend.h b/src/llmq/quorums_instantsend.h index 2c5fdb88fba2d..bb696b4adef73 100644 --- a/src/llmq/quorums_instantsend.h +++ b/src/llmq/quorums_instantsend.h @@ -137,6 +137,7 @@ class CInstantSendManager : public CRecoveredSigsListener void ProcessMessageInstantSendLock(CNode* pfrom, const CInstantSendLock& islock, CConnman& connman); bool PreVerifyInstantSendLock(NodeId nodeId, const CInstantSendLock& islock, bool& retBan); bool ProcessPendingInstantSendLocks(); + std::unordered_set ProcessPendingInstantSendLocks(int signHeight, const std::unordered_map>& pend, bool ban); void ProcessInstantSendLock(NodeId from, const uint256& hash, const CInstantSendLock& islock); void UpdateWalletTransaction(const uint256& txid, const CTransactionRef& tx); diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index d5b9a79b2dbdf..39fad65af763b 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -849,7 +849,7 @@ bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256& return db.GetVoteForId(llmqType, id, msgHashRet); } -CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType, int signHeight, const uint256& selectionHash) +std::vector CSigningManager::GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight) { auto& llmqParams = Params().GetConsensus().llmqs.at(llmqType); size_t poolSize = (size_t)llmqParams.signingActiveQuorumCount; @@ -859,12 +859,17 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType LOCK(cs_main); int startBlockHeight = signHeight - SIGN_HEIGHT_OFFSET; if (startBlockHeight > chainActive.Height()) { - return nullptr; + return {}; } pindexStart = chainActive[startBlockHeight]; } - auto quorums = quorumManager->ScanQuorums(llmqType, pindexStart, poolSize); + return quorumManager->ScanQuorums(llmqType, pindexStart, poolSize); +} + +CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType, int signHeight, const uint256& selectionHash) +{ + auto quorums = GetActiveQuorumSet(llmqType, signHeight); if (quorums.empty()) { return nullptr; } diff --git a/src/llmq/quorums_signing.h b/src/llmq/quorums_signing.h index f6e3f3873328d..c4c5343032fc7 100644 --- a/src/llmq/quorums_signing.h +++ b/src/llmq/quorums_signing.h @@ -177,6 +177,7 @@ class CSigningManager bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id); bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet); + std::vector GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight); CQuorumCPtr SelectQuorumForSigning(Consensus::LLMQType llmqType, int signHeight, const uint256& selectionHash); // Verifies a recovered sig that was signed while the chain tip was at signedAtTip From 788d42dbcf2ac690717f4a5a55e19ec29bad1ecb Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 12 Aug 2019 20:08:33 +0200 Subject: [PATCH 17/19] Bump version to 0.14.0.3 and copy release notes (#3053) --- configure.ac | 2 +- doc/Doxyfile | 2 +- doc/release-notes.md | 2 +- .../dash/release-notes-0.14.0.2.md | 133 ++++++++++++++++++ src/clientversion.h | 2 +- 5 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 doc/release-notes/dash/release-notes-0.14.0.2.md diff --git a/configure.ac b/configure.ac index c3c6dc3145891..c0508d62de7bb 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 14) define(_CLIENT_VERSION_REVISION, 0) -define(_CLIENT_VERSION_BUILD, 2) +define(_CLIENT_VERSION_BUILD, 3) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2019) define(_COPYRIGHT_HOLDERS,[The %s developers]) diff --git a/doc/Doxyfile b/doc/Doxyfile index 400a4edb763b2..e44ff6938b532 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -41,7 +41,7 @@ PROJECT_NAME = "Dash Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.14.0.2 +PROJECT_NUMBER = 0.14.0.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/release-notes.md b/doc/release-notes.md index 30554c52dfdbb..ca5f36d14f18d 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,4 +1,4 @@ -Dash Core version 0.14.0.2 +Dash Core version 0.14.0.3 ========================== Release is now available from: diff --git a/doc/release-notes/dash/release-notes-0.14.0.2.md b/doc/release-notes/dash/release-notes-0.14.0.2.md new file mode 100644 index 0000000000000..30554c52dfdbb --- /dev/null +++ b/doc/release-notes/dash/release-notes-0.14.0.2.md @@ -0,0 +1,133 @@ +Dash Core version 0.14.0.2 +========================== + +Release is now available from: + + + +This is a new minor version release, bringing various bugfixes. + +Please report bugs using the issue tracker at github: + + + + +Upgrading and downgrading +========================= + +How to Upgrade +-------------- + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over /Applications/Dash-Qt (on Mac) or +dashd/dash-qt (on Linux). If you upgrade after DIP0003 activation and you were +using version < 0.13 you will have to reindex (start with -reindex-chainstate +or -reindex) to make sure your wallet has all the new data synced. Upgrading from +version 0.13 should not require any additional actions. + +Downgrade warning +----------------- + +### Downgrade to a version < 0.14.0.0 + +Downgrading to a version smaller than 0.14 is not supported anymore as DIP8 has +activated on mainnet and testnet. + +### Downgrade to versions 0.14.0.0 - 0.14.0.1 + +Downgrading to older 0.14 releases is fully supported but is not +recommended unless you have some serious issues with version 0.14.0.2. + +Notable changes +=============== + +Performance improvements +------------------------ +Slow startup times were observed in older versions. This was due to sub-optimal handling of old +deterministic masternode lists which caused the loading of too many lists into memory. This should be +fixed now. + +Fixed excessive memory use +-------------------------- +Multiple issues were found which caused excessive use of memory in some situations, especially when +a full reindex was performed, causing the node to crash even when enough RAM was available. This should +be fixed now. + +Fixed out-of-sync masternode list UI +------------------------------------ +The masternode tab, which shows the masternode list, was not always up-to-date as it missed some internal +updates. This should be fixed now. + +0.14.0.2 Change log +=================== + +See detailed [set of changes](https://github.com/dashpay/dash/compare/v0.14.0.1...dashpay:v0.14.0.2). + +- [`d2ff63e8d`](https://github.com/dashpay/dash/commit/d2ff63e8d) Use std::unique_ptr for mnList in CSimplifiedMNList (#3014) +- [`321bbf5af`](https://github.com/dashpay/dash/commit/321bbf5af) Fix excessive memory use when flushing chainstate and EvoDB (#3008) +- [`0410259dd`](https://github.com/dashpay/dash/commit/0410259dd) Fix 2 common Travis failures which happen when Travis has network issues (#3003) +- [`8d763c144`](https://github.com/dashpay/dash/commit/8d763c144) Only load signingActiveQuorumCount + 1 quorums into cache (#3002) +- [`2dc1b06ec`](https://github.com/dashpay/dash/commit/2dc1b06ec) Remove skipped denom from the list on tx commit (#2997) +- [`dff2c851d`](https://github.com/dashpay/dash/commit/dff2c851d) Update manpages for 0.14.0.2 (#2999) +- [`46c4f5844`](https://github.com/dashpay/dash/commit/46c4f5844) Use Travis stages instead of custom timeouts (#2948) +- [`49c37b82a`](https://github.com/dashpay/dash/commit/49c37b82a) Back off for 1m when connecting to quorum masternodes (#2975) +- [`c1f756fd9`](https://github.com/dashpay/dash/commit/c1f756fd9) Multiple speed optimizations for deterministic MN list handling (#2972) +- [`11699f540`](https://github.com/dashpay/dash/commit/11699f540) Process/keep messages/connections from PoSe-banned MNs (#2967) +- [`c5415e746`](https://github.com/dashpay/dash/commit/c5415e746) Fix UI masternode list (#2966) +- [`fb6f0e04d`](https://github.com/dashpay/dash/commit/fb6f0e04d) Bump version to 0.14.0.2 and copy release notes (#2991) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Alexander Block (codablock) +- UdjinM6 + +As well as everyone that submitted issues and reviewed pull requests. + +Older releases +============== + +Dash was previously known as Darkcoin. + +Darkcoin tree 0.8.x was a fork of Litecoin tree 0.8, original name was XCoin +which was first released on Jan/18/2014. + +Darkcoin tree 0.9.x was the open source implementation of masternodes based on +the 0.8.x tree and was first released on Mar/13/2014. + +Darkcoin tree 0.10.x used to be the closed source implementation of Darksend +which was released open source on Sep/25/2014. + +Dash Core tree 0.11.x was a fork of Bitcoin Core tree 0.9, +Darkcoin was rebranded to Dash. + +Dash Core tree 0.12.0.x was a fork of Bitcoin Core tree 0.10. + +Dash Core tree 0.12.1.x was a fork of Bitcoin Core tree 0.12. + +These release are considered obsolete. Old release notes can be found here: + +- [v0.14.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.1.md) released May/31/2019 +- [v0.14.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.md) released May/22/2019 +- [v0.13.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.3.md) released Apr/04/2019 +- [v0.13.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.2.md) released Mar/15/2019 +- [v0.13.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.1.md) released Feb/9/2019 +- [v0.13.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.0.md) released Jan/14/2019 +- [v0.12.3.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.4.md) released Dec/14/2018 +- [v0.12.3.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.3.md) released Sep/19/2018 +- [v0.12.3.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.2.md) released Jul/09/2018 +- [v0.12.3.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.1.md) released Jul/03/2018 +- [v0.12.2.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.3.md) released Jan/12/2018 +- [v0.12.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.2.md) released Dec/17/2017 +- [v0.12.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.md) released Nov/08/2017 +- [v0.12.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.1.md) released Feb/06/2017 +- [v0.12.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.0.md) released Aug/15/2015 +- [v0.11.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.2.md) released Mar/04/2015 +- [v0.11.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.1.md) released Feb/10/2015 +- [v0.11.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.0.md) released Jan/15/2015 +- [v0.10.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.10.0.md) released Sep/25/2014 +- [v0.9.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.9.0.md) released Mar/13/2014 + diff --git a/src/clientversion.h b/src/clientversion.h index 5f1ea03d31df3..a03ca0eb32318 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,7 +17,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 14 #define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 2 +#define CLIENT_VERSION_BUILD 3 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true From f2443709b38bc672d7c255f55aacf47774c6d73c Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 13 Aug 2019 19:33:52 +0200 Subject: [PATCH 18/19] Update release-notes.md for 0.14.0.3 (#3054) --- doc/release-notes.md | 100 ++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index ca5f36d14f18d..9cb12adbc7693 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -5,7 +5,7 @@ Release is now available from: -This is a new minor version release, bringing various bugfixes. +This is a new minor version release, bringing various bugfixes and improvements. Please report bugs using the issue tracker at github: @@ -26,56 +26,72 @@ using version < 0.13 you will have to reindex (start with -reindex-chainstate or -reindex) to make sure your wallet has all the new data synced. Upgrading from version 0.13 should not require any additional actions. +Due to the changes in the "evodb" database format introduced in this release, the +first startup of Dash Core will run a migration process which can take a few minutes +to finish. After the migration, a downgrade to an older version is only possible with +a reindex (or reindex-chainstate). + Downgrade warning ----------------- -### Downgrade to a version < 0.14.0.0 - -Downgrading to a version smaller than 0.14 is not supported anymore as DIP8 has -activated on mainnet and testnet. - -### Downgrade to versions 0.14.0.0 - 0.14.0.1 +### Downgrade to a version < 0.14.0.3 -Downgrading to older 0.14 releases is fully supported but is not -recommended unless you have some serious issues with version 0.14.0.2. +Downgrading to a version smaller than 0.14.0.3 is not supported anymore due to changes +in the "evodb" database format. If you need to use an older version, you have to perform +a reindex or re-sync the whole chain. Notable changes =============== -Performance improvements ------------------------- -Slow startup times were observed in older versions. This was due to sub-optimal handling of old -deterministic masternode lists which caused the loading of too many lists into memory. This should be -fixed now. - -Fixed excessive memory use --------------------------- -Multiple issues were found which caused excessive use of memory in some situations, especially when -a full reindex was performed, causing the node to crash even when enough RAM was available. This should -be fixed now. +Database space usage improvements +-------------------------------- +Version 0.13.0.0 introduced a new database (evodb) which is found in the datadir of Dash Core. It turned +out that this database grows quite fast when a lot of changes inside the deterministic masternode list happen, +which is for example the case when a lot PoSe punishing/banning is happening. Such a situation happened +immediately after the activation LLMQ DKGs, causing the database to grow a lot. This release introduces +a new format in which information in "evodb" is stored, which causes it grow substantially slower. + +Version 0.14.0.0 also introduced a new database (llmq) which is also found in the datadir of Dash Core. +This database stores all LLMQ signatures for 7 days. After 7 days, a cleanup task removes old signatures. +The idea was that the "llmq" database would grow in the beginning and then stay at an approximately constant +size. The recent stress test on mainnet has however shown that the database grows too much and causes a risk +of out-of-space situations. This release will from now also remove signatures when the corresponding InstantSend +lock is fully confirmed on-chain (superseded by a ChainLock). This should remove >95% of all signatures from +the database. After the upgrade, no space saving will be observed however as this logic is only applied to new +signatures, which means that it will take 7 days until the whole "llmq" database gets to its minimum size. + +DKG and LLMQ signing failures fixed +----------------------------------- +Recent stress tests have shown that masternodes start to ban each other under high load and specific situations. +This release fixes this and thus makes it a highly recommended upgrade for masternodes. + +MacOS: macOS: disable AppNap during sync and mixing +--------------------------------------------------- +AppNap is disabled now when Dash Core is syncing/reindexing or mixing. + +Signed binaries for Windows +--------------------------- +This release is the first one to include signed binaries for Windows. + +New RPC command: quorum memberof +-------------------------------------------- +This RPC allows you to verify which quorums a masternode is supposed to be a member of. It will also show +if the masternode succesfully participated in the DKG process. + +More information about number of InstantSend locks +-------------------------------------------------- +The debug console will now show how many InstantSend locks Dash Core knows about. Please note that this number +does not necessarily equal the number of mempool transactions. + +The "getmempoolinfo" RPC also has a new field now which shows the same information. + +0.14.0.3 Change log +=================== -Fixed out-of-sync masternode list UI ------------------------------------- -The masternode tab, which shows the masternode list, was not always up-to-date as it missed some internal -updates. This should be fixed now. +TODO -0.14.0.2 Change log -=================== +See detailed [set of changes](https://github.com/dashpay/dash/compare/v0.14.0.2...dashpay:v0.14.0.3). -See detailed [set of changes](https://github.com/dashpay/dash/compare/v0.14.0.1...dashpay:v0.14.0.2). - -- [`d2ff63e8d`](https://github.com/dashpay/dash/commit/d2ff63e8d) Use std::unique_ptr for mnList in CSimplifiedMNList (#3014) -- [`321bbf5af`](https://github.com/dashpay/dash/commit/321bbf5af) Fix excessive memory use when flushing chainstate and EvoDB (#3008) -- [`0410259dd`](https://github.com/dashpay/dash/commit/0410259dd) Fix 2 common Travis failures which happen when Travis has network issues (#3003) -- [`8d763c144`](https://github.com/dashpay/dash/commit/8d763c144) Only load signingActiveQuorumCount + 1 quorums into cache (#3002) -- [`2dc1b06ec`](https://github.com/dashpay/dash/commit/2dc1b06ec) Remove skipped denom from the list on tx commit (#2997) -- [`dff2c851d`](https://github.com/dashpay/dash/commit/dff2c851d) Update manpages for 0.14.0.2 (#2999) -- [`46c4f5844`](https://github.com/dashpay/dash/commit/46c4f5844) Use Travis stages instead of custom timeouts (#2948) -- [`49c37b82a`](https://github.com/dashpay/dash/commit/49c37b82a) Back off for 1m when connecting to quorum masternodes (#2975) -- [`c1f756fd9`](https://github.com/dashpay/dash/commit/c1f756fd9) Multiple speed optimizations for deterministic MN list handling (#2972) -- [`11699f540`](https://github.com/dashpay/dash/commit/11699f540) Process/keep messages/connections from PoSe-banned MNs (#2967) -- [`c5415e746`](https://github.com/dashpay/dash/commit/c5415e746) Fix UI masternode list (#2966) -- [`fb6f0e04d`](https://github.com/dashpay/dash/commit/fb6f0e04d) Bump version to 0.14.0.2 and copy release notes (#2991) Credits ======= @@ -83,6 +99,9 @@ Credits Thanks to everyone who directly contributed to this release: - Alexander Block (codablock) +- Nathan Marley (nmarley) +- PastaPastaPasta +- strophy - UdjinM6 As well as everyone that submitted issues and reviewed pull requests. @@ -110,6 +129,7 @@ Dash Core tree 0.12.1.x was a fork of Bitcoin Core tree 0.12. These release are considered obsolete. Old release notes can be found here: +- [v0.14.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.2.md) released July/4/2019 - [v0.14.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.1.md) released May/31/2019 - [v0.14.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.md) released May/22/2019 - [v0.13.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.3.md) released Apr/04/2019 From 7d8eab2641023c78a72ccd6efc99fc35fd030a46 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 14 Aug 2019 04:51:13 +0200 Subject: [PATCH 19/19] Add 0.14.0.3 change log to release-notes.md (#3055) --- doc/release-notes.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 9cb12adbc7693..ab7b4288da914 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -88,10 +88,26 @@ The "getmempoolinfo" RPC also has a new field now which shows the same informati 0.14.0.3 Change log =================== -TODO - See detailed [set of changes](https://github.com/dashpay/dash/compare/v0.14.0.2...dashpay:v0.14.0.3). +- [`f2443709b`](https://github.com/dashpay/dash/commit/f2443709b) Update release-notes.md for 0.14.0.3 (#3054) +- [`17ba23871`](https://github.com/dashpay/dash/commit/17ba23871) Re-verify invalid IS sigs when the active quorum set rotated (#3052) +- [`8c49d9b54`](https://github.com/dashpay/dash/commit/8c49d9b54) Remove recovered sigs from the LLMQ db when corresponding IS locks get confirmed (#3048) +- [`2e0cf8a30`](https://github.com/dashpay/dash/commit/2e0cf8a30) Add "instantsendlocks" to getmempoolinfo RPC (#3047) +- [`a8fb8252e`](https://github.com/dashpay/dash/commit/a8fb8252e) Use fEnablePrivateSend instead of fPrivateSendRunning +- [`a198a04e0`](https://github.com/dashpay/dash/commit/a198a04e0) Show number of InstantSend locks in Debug Console (#2919) +- [`013169d63`](https://github.com/dashpay/dash/commit/013169d63) Optimize on-disk deterministic masternode storage to reduce size of evodb (#3017) +- [`9ac7a998b`](https://github.com/dashpay/dash/commit/9ac7a998b) Add "isValidMember" and "memberIndex" to "quorum memberof" and allow to specify quorum scan count (#3009) +- [`99824a879`](https://github.com/dashpay/dash/commit/99824a879) Implement "quorum memberof" (#3004) +- [`7ea319fd2`](https://github.com/dashpay/dash/commit/7ea319fd2) Bail out properly on Evo DB consistency check failures in ConnectBlock/DisconnectBlock (#3044) +- [`b1ffedb2d`](https://github.com/dashpay/dash/commit/b1ffedb2d) Do not count 0-fee txes for fee estimation (#3037) +- [`974055a9b`](https://github.com/dashpay/dash/commit/974055a9b) Fix broken link in PrivateSend info dialog (#3031) +- [`781b16579`](https://github.com/dashpay/dash/commit/781b16579) Merge pull request #3028 from PastaPastaPasta/backport-12588 +- [`5af6ce91d`](https://github.com/dashpay/dash/commit/5af6ce91d) Add Dash Core Group codesign certificate (#3027) +- [`873ab896c`](https://github.com/dashpay/dash/commit/873ab896c) Fix osslsigncode compile issue in gitian-build (#3026) +- [`ea8569e97`](https://github.com/dashpay/dash/commit/ea8569e97) Backport #12783: macOS: disable AppNap during sync (and mixing) (#3024) +- [`4286dde49`](https://github.com/dashpay/dash/commit/4286dde49) Remove support for InstantSend locked gobject collaterals (#3019) +- [`788d42dbc`](https://github.com/dashpay/dash/commit/788d42dbc) Bump version to 0.14.0.3 and copy release notes (#3053) Credits =======