mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge pull request #5427 from PastaPastaPasta/v19.2-rc.1-backports
backport: V19.2 rc.1 backports
This commit is contained in:
commit
44cd30f2f7
12
configure.ac
12
configure.ac
@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.69])
|
||||
define(_CLIENT_VERSION_MAJOR, 19)
|
||||
define(_CLIENT_VERSION_MINOR, 1)
|
||||
define(_CLIENT_VERSION_MINOR, 2)
|
||||
define(_CLIENT_VERSION_BUILD, 0)
|
||||
define(_CLIENT_VERSION_RC, 0)
|
||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||
define(_CLIENT_VERSION_RC, 1)
|
||||
define(_CLIENT_VERSION_IS_RELEASE, false)
|
||||
define(_COPYRIGHT_YEAR, 2023)
|
||||
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
||||
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Dash Core]])
|
||||
@ -713,6 +713,12 @@ case $host in
|
||||
export PKG_CONFIG_PATH
|
||||
fi
|
||||
|
||||
gmp_prefix=$($BREW --prefix gmp 2>/dev/null)
|
||||
if test x$gmp_prefix != x; then
|
||||
CPPFLAGS="$CPPFLAGS -I$gmp_prefix/include"
|
||||
LDFLAGS="$LDFLAGS -L$gmp_prefix/lib"
|
||||
fi
|
||||
|
||||
case $host in
|
||||
*aarch64*)
|
||||
dnl The preferred Homebrew prefix for Apple Silicon is /opt/homebrew.
|
||||
|
@ -1,6 +1,6 @@
|
||||
PACKAGE=qt
|
||||
$(package)_version=5.12.11
|
||||
$(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules
|
||||
$(package)_download_path=https://download.qt.io/archive/qt/5.12/$($(package)_version)/submodules
|
||||
$(package)_suffix=everywhere-src-$($(package)_version).tar.xz
|
||||
$(package)_file_name=qtbase-$($(package)_suffix)
|
||||
$(package)_sha256_hash=1c1b4e33137ca77881074c140d54c3c9747e845a31338cfe8680f171f0bc3a39
|
||||
|
289
doc/release-notes/dash/release-notes-19.0.0.md
Normal file
289
doc/release-notes/dash/release-notes-19.0.0.md
Normal file
@ -0,0 +1,289 @@
|
||||
# Dash Core version v19.0.0
|
||||
|
||||
Release is now available from:
|
||||
|
||||
<https://www.dash.org/downloads/#wallets>
|
||||
|
||||
This is a new major version release, bringing new features, various bugfixes
|
||||
and other improvements.
|
||||
|
||||
This release is mandatory for all nodes.
|
||||
|
||||
Please report bugs using the issue tracker at GitHub:
|
||||
|
||||
<https://github.com/dashpay/dash/issues>
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
When upgrading from a version prior to 18.0.1, the
|
||||
first startup of Dash Core will run a migration process which can take anywhere
|
||||
from a few minutes to thirty 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 < v19.0.0
|
||||
Downgrading to a version older than v19.0.0 is not supported due to changes in the evodb database. If you need to use an older version, you must either reindex or re-sync the whole chain.
|
||||
|
||||
# Notable changes
|
||||
|
||||
## High-Performance Masternodes
|
||||
|
||||
In preparation for the release of Dash Platform to mainnet, a new masternode type has been added. High-performance masternodes will be responsible for hosting Dash Platform services (once they are on mainnet) in addition to the existing responsibilities like ChainLocks and InstantSend.
|
||||
|
||||
Activation of the DashCore v19.0 hard fork will enable registration of the new 4000 DASH collateral masternodes. Until Dash Platform is released to mainnet, high-performance masternodes will provide the same services as regular masternodes with one small exception. Regular masternodes will no longer participate in the Platform-specific LLMQ after the hard fork since they will not be responsible for hosting Dash Platform.
|
||||
|
||||
Note: In DashCore v19.0 the relative rewards and voting power are equivalent between regular and high-performance masternodes. Masternodes effectively receive one payout and one governance vote per 1000 DASH collateral. So, there is no difference in reward amount for running four regular masternodes or one high-performance masternode. In v19.0, high-performance masternodes simply receive payments in four consecutive blocks when they are selected for payout. Some frequently asked questions may be found at https://www.dash.org/hpmn-faq/.
|
||||
|
||||
## BLS Scheme Upgrade
|
||||
|
||||
Once the v19 hard fork is activated, all remaining messages containing BLS public keys or signatures will serialise them using the new basic BLS scheme.
|
||||
The motivation behind this change is the need to be aligned with IETF standards.
|
||||
|
||||
List of affected messages:
|
||||
`dsq`, `dstx`, `mnauth`, `govobj`, `govobjvote`, `qrinfo`, `qsigshare`, `qsigrec`, `isdlock`, `clsig`, and all DKG messages (`qfcommit`, `qcontrib`, `qcomplaint`, `qjustify`, `qpcommit`).
|
||||
|
||||
### `qfcommit`
|
||||
|
||||
Once the v19 hard fork is activated, `quorumPublicKey` will be serialised using the basic BLS scheme.
|
||||
To support syncing of older blocks containing the transactions using the legacy BLS scheme, the `version` field indicates which scheme to use for serialisation of `quorumPublicKey`.
|
||||
|
||||
| Version | Version Description | Includes `quorumIndex` field |
|
||||
|---------|--------------------------------------------------------|------------------------------|
|
||||
| 1 | Non-rotated qfcommit serialised using legacy BLS scheme | No |
|
||||
| 2 | Rotated qfcommit serialised using legacy BLS scheme | Yes |
|
||||
| 3 | Non-rotated qfcommit serialised using basic BLS scheme | No |
|
||||
| 4 | Rotated qfcommit serialised using basic BLS scheme | Yes |
|
||||
|
||||
### `MNLISTDIFF` P2P message
|
||||
|
||||
Starting with protocol version 70225, the following field is added to the `MNLISTDIFF` message between `cbTx` and `deletedQuorumsCount`.
|
||||
|
||||
| Field | Type | Size | Description |
|
||||
|---------------------| ---- | ---- |-----------------------------------|
|
||||
| version | uint16_t | 2 | Version of the `MNLISTDIFF` reply |
|
||||
|
||||
The `version` field indicates which BLS scheme is used to serialise the `pubKeyOperator` field for all SML entries of `mnList`.
|
||||
|
||||
| Version | Version Description |
|
||||
|---------|-----------------------------------------------------------|
|
||||
| 1 | Serialisation of `pubKeyOperator` using legacy BLS scheme |
|
||||
| 2 | Serialisation of `pubKeyOperator` using basic BLS scheme |
|
||||
|
||||
### `ProTx` txs family
|
||||
|
||||
`proregtx` and `proupregtx` will support a new `version` value:
|
||||
|
||||
| Version | Version Description |
|
||||
|---------|-----------------------------------------------------------|
|
||||
| 1 | Serialisation of `pubKeyOperator` using legacy BLS scheme |
|
||||
| 2 | Serialisation of `pubKeyOperator` using basic BLS scheme |
|
||||
|
||||
`proupservtx` and `prouprevtx` will support a new `version` value:
|
||||
|
||||
| Version | Version Description |
|
||||
|---------|------------------------------------------------|
|
||||
| 1 | Serialisation of `sig` using legacy BLS scheme |
|
||||
| 2 | Serialisation of `sig` using basic BLS scheme |
|
||||
|
||||
### `MNHFTx`
|
||||
|
||||
`MNHFTx` will support a new `version` value:
|
||||
|
||||
| Version | Version Description |
|
||||
|---------|------------------------------------------------|
|
||||
| 1 | Serialisation of `sig` using legacy BLS scheme |
|
||||
| 2 | Serialisation of `sig` using basic BLS scheme |
|
||||
|
||||
## Wallet
|
||||
|
||||
## Automatic wallet creation removed
|
||||
|
||||
Dash Core will no longer automatically create new wallets on startup. It will
|
||||
load existing wallets specified by -wallet options on the command line or in
|
||||
dash.conf or settings.json files. And by default it will also load a
|
||||
top-level unnamed ("") wallet. However, if specified wallets don't exist,
|
||||
Dash Core will now just log warnings instead of creating new wallets with
|
||||
new keys and addresses like previous releases did.
|
||||
|
||||
New wallets can be created through the GUI (which has a more prominent create
|
||||
wallet option), through the dash-wallet create command or the createwallet RPC.
|
||||
|
||||
## P2P and Network Changes
|
||||
|
||||
## Removal of reject network messages from Dash Core (BIP61)
|
||||
|
||||
The command line option to enable BIP61 (-enablebip61) has been removed.
|
||||
|
||||
Nodes on the network can not generally be trusted to send valid ("reject")
|
||||
messages, so this should only ever be used when connected to a trusted node.
|
||||
Please use the recommended alternatives if you rely on this deprecated feature:
|
||||
|
||||
- Testing or debugging of implementations of the Dash P2P network protocol
|
||||
should be done by inspecting the log messages that are produced by a recent
|
||||
version of Dash Core. Dash Core logs debug messages
|
||||
(-debug=<category>) to a stream (-printtoconsole) or to a file
|
||||
(-debuglogfile=<debug.log>).
|
||||
|
||||
- Testing the validity of a block can be achieved by specific RPCs:
|
||||
- submitblock
|
||||
- getblocktemplate with 'mode' set to 'proposal' for blocks with
|
||||
- potentially invalid POW
|
||||
- Testing the validity of a transaction can be achieved by specific RPCs:
|
||||
- sendrawtransaction
|
||||
- testmempoolaccept
|
||||
|
||||
## CoinJoin update
|
||||
|
||||
A minor update in several CoinJoin-related network messages improves support
|
||||
for mixing from SPV clients. These changes make it easier for SPV clients to
|
||||
participate in the CoinJoin process by using masternode information they can
|
||||
readily obtain and verify via [DIP-0004](https://github.com/dashpay/dips/blob/master/dip-0004.md).
|
||||
|
||||
## Remote Procedure Call (RPC) Changes
|
||||
|
||||
### The new RPCs are:
|
||||
- In order to support BLS public keys encoded in the legacy BLS scheme, `protx register_legacy`, `protx register_fund_legacy`, and `protx register_prepare_legacy` were added.
|
||||
- `cleardiscouraged` clears all the already discouraged peers.
|
||||
- The following RPCs were added: `protx register_hpmn`, `protx register_fund_hpmn`, `protx register_prepare_hpmn` and `protx update_service_hpmn`.
|
||||
These HPMN RPCs correspond to the standard masternode RPCs but have the following additional mandatory arguments: `platformNodeID`, `platformP2PPort` and `platformHTTPPort`.
|
||||
- `upgradewallet`
|
||||
|
||||
### The removed RPCs are:
|
||||
|
||||
None
|
||||
|
||||
### Changes in existing RPCs introduced through bitcoin backports:
|
||||
|
||||
- The `utxoupdatepsbt` RPC method has been updated to take a descriptors
|
||||
argument. When provided, input and output scripts and keys will be filled in
|
||||
when known. See the RPC help text for full details.
|
||||
|
||||
|
||||
### Dash-specific changes in existing RPCs:
|
||||
|
||||
- `masternodelist`: New mode `recent` was added in order to hide banned masternodes for more than one `SuperblockCycle`. If the mode `recent` is used, then the reply mode is JSON (can be additionally filtered)
|
||||
- `quorum info`: The new `previousConsecutiveDKGFailures` field will be returned for rotated LLMQs. This field will hold the number of previous consecutive DKG failures for the corresponding quorumIndex before the currently active one. Note: If no previous commitments were found then 0 will be returned for `previousConsecutiveDKGFailures`.
|
||||
- `bls generate` and `bls fromsecret`: The new `scheme` field will be returned indicating which scheme was used to serialise the public key. Valid returned values are `legacy` and`basic`.
|
||||
- `bls generate` and `bls fromsecret`: Both RPCs accept an incoming optional boolean argument `legacy` that enforces the use of legacy BLS scheme for the serialisation of the reply even if v19 is active.
|
||||
- `masternode status`: now returns the type of the masternode.
|
||||
- `masternode count`: now returns a detailed summary of total and enabled masternodes per type.
|
||||
- `gobject getcurrentvotes`: reply is enriched by adding the vote weight at the end of each line. Possible values are 1 or 4. Example: "7cb20c883c6093b8489f795b3ec0aad0d9c2c2821610ae9ed938baaf42fec66d": "277e6345359071410ab691c21a3a16f8f46c9229c2f8ec8f028c9a95c0f1c0e7-1:1670019339:yes:funding:4"
|
||||
- Once the v19 hard fork is activated, `protx register`, `protx register_fund`, and `protx register_prepare` RPCs will decode BLS operator public keys using the new basic BLS scheme.
|
||||
|
||||
Please check `help <command>` for more detailed information on specific RPCs.
|
||||
|
||||
## Command-line options
|
||||
|
||||
A number of command-line option changes were made related to testing and
|
||||
removal of BIP61 support.
|
||||
|
||||
New cmd-line options:
|
||||
- `llmqplatform` (devnet only)
|
||||
- `unsafesqlitesync`
|
||||
|
||||
Removed cmd-line options:
|
||||
- `enablebip61`
|
||||
- `upgradewallet`
|
||||
|
||||
Changes in existing cmd-line options:
|
||||
- `llmqinstantsend` and `llmqinstantsenddip0024` can be used in regtest now
|
||||
- Passing an invalid `-rpcauth` argument now cause dashd to fail to start.
|
||||
|
||||
Please check `Help -> Command-line options` in Qt wallet or `dashd --help` for
|
||||
more information.
|
||||
|
||||
## Backports from Bitcoin Core
|
||||
|
||||
This release introduces many updates from Bitcoin v0.18-v0.21 as well as numerous updates from Bitcoin v22 and more recent versions. Bitcoin changes that do not align with Dash’s product needs, such as SegWit and RBF, are excluded from our backporting. For additional detail on what’s included in Bitcoin, please refer to their release notes.
|
||||
|
||||
# v19.0.0 Change log
|
||||
|
||||
See detailed [set of changes](https://github.com/dashpay/dash/compare/v18.2.2...dashpay:v19.0.0).
|
||||
|
||||
# Credits
|
||||
|
||||
Thanks to everyone who directly contributed to this release:
|
||||
|
||||
- Kittywhiskers Van Gogh (kittywhiskers)
|
||||
- Konstantin Akimov (knst)
|
||||
- Odysseas Gabrielides (ogabrielides)
|
||||
- Oleg Girko (OlegGirko)
|
||||
- PastaPastaPasta
|
||||
- thephez
|
||||
- UdjinM6
|
||||
- Vijay Das Manikpuri (vijaydasmp)
|
||||
|
||||
As well as everyone that submitted issues, reviewed pull requests, helped debug the release candidates, and write DIPs that were implemented in this release.
|
||||
|
||||
# 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:
|
||||
|
||||
- [v18.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.2.md) released Mar/21/2023
|
||||
- [v18.2.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.1.md) released Jan/17/2023
|
||||
- [v18.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.0.md) released Jan/01/2023
|
||||
- [v18.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.1.md) released January/08/2023
|
||||
- [v18.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.0.md) released October/09/2022
|
||||
- [v18.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.2.md) released October/09/2022
|
||||
- [v18.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.1.md) released August/17/2022
|
||||
- [v0.17.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.3.md) released June/07/2021
|
||||
- [v0.17.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.2.md) released May/19/2021
|
||||
- [v0.16.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.1.md) released November/17/2020
|
||||
- [v0.16.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.0.md) released November/14/2020
|
||||
- [v0.16.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.0.1.md) released September/30/2020
|
||||
- [v0.15.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.15.0.0.md) released Febrary/18/2020
|
||||
- [v0.14.0.5](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.5.md) released December/08/2019
|
||||
- [v0.14.0.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.4.md) released November/22/2019
|
||||
- [v0.14.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.3.md) released August/15/2019
|
||||
- [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
|
||||
- [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
|
@ -147,11 +147,11 @@ bool CMnemonic::Check(SecureString mnemonic)
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// passphrase must be at most 256 characters or code may crash
|
||||
// passphrase must be at most 256 characters otherwise it would be truncated
|
||||
void CMnemonic::ToSeed(SecureString mnemonic, SecureString passphrase, SecureVector& seedRet)
|
||||
{
|
||||
SecureString ssSalt = SecureString("mnemonic") + passphrase;
|
||||
SecureVector vchSalt(ssSalt.begin(), ssSalt.end());
|
||||
SecureVector vchSalt(ssSalt.begin(), ssSalt.begin() + strnlen(ssSalt.data(), 256));
|
||||
seedRet.resize(64);
|
||||
PKCS5_PBKDF2_HMAC_SHA512(mnemonic.c_str(), mnemonic.size(), vchSalt.data(), vchSalt.size(), 2048, 64, seedRet.data());
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
static SecureString Generate(int strength); // strength in bits
|
||||
static SecureString FromData(const SecureVector& data, int len);
|
||||
static bool Check(SecureString mnemonic);
|
||||
// passphrase must be at most 256 characters or code may crash
|
||||
// passphrase must be at most 256 characters otherwise it would be truncated
|
||||
static void ToSeed(SecureString mnemonic, SecureString passphrase, SecureVector& seedRet);
|
||||
};
|
||||
|
||||
|
@ -418,10 +418,7 @@ public:
|
||||
CBLSLazyWrapper() :
|
||||
vecBytes(BLSObject::SerSize, 0),
|
||||
bufLegacyScheme(bls::bls_legacy_scheme.load())
|
||||
{
|
||||
// the all-zero buf is considered a valid buf, but the resulting object will return false for IsValid
|
||||
bufValid = true;
|
||||
}
|
||||
{}
|
||||
|
||||
explicit CBLSLazyWrapper(const CBLSLazyWrapper& r)
|
||||
{
|
||||
@ -437,6 +434,7 @@ public:
|
||||
if (r.bufValid) {
|
||||
vecBytes = r.vecBytes;
|
||||
} else {
|
||||
vecBytes.resize(BLSObject::SerSize);
|
||||
std::fill(vecBytes.begin(), vecBytes.end(), 0);
|
||||
}
|
||||
objInitialized = r.objInitialized;
|
||||
@ -459,12 +457,9 @@ public:
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mutex);
|
||||
if (!objInitialized && !bufValid) {
|
||||
// the all-zero buf is considered a valid buf
|
||||
vecBytes.resize(BLSObject::SerSize);
|
||||
std::fill(vecBytes.begin(), vecBytes.end(), 0);
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
bufValid = true;
|
||||
}
|
||||
if (!bufValid || (bufLegacyScheme != specificLegacyScheme)) {
|
||||
} else if (!bufValid || (bufLegacyScheme != specificLegacyScheme)) {
|
||||
vecBytes = obj.ToByteVector(specificLegacyScheme);
|
||||
bufValid = true;
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
@ -476,7 +471,7 @@ public:
|
||||
template<typename Stream>
|
||||
inline void Serialize(Stream& s) const
|
||||
{
|
||||
Serialize(s, bls::bls_legacy_scheme.load());
|
||||
Serialize(s, bufLegacyScheme);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
@ -493,13 +488,14 @@ public:
|
||||
template<typename Stream>
|
||||
inline void Unserialize(Stream& s) const
|
||||
{
|
||||
Unserialize(s, bls::bls_legacy_scheme.load());
|
||||
Unserialize(s, bufLegacyScheme);
|
||||
}
|
||||
|
||||
void Set(const BLSObject& _obj)
|
||||
void Set(const BLSObject& _obj, const bool specificLegacyScheme)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mutex);
|
||||
bufValid = false;
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
objInitialized = true;
|
||||
obj = _obj;
|
||||
hash.SetNull();
|
||||
@ -514,21 +510,14 @@ public:
|
||||
if (!objInitialized) {
|
||||
obj.SetByteVector(vecBytes, bufLegacyScheme);
|
||||
if (!obj.IsValid()) {
|
||||
// If setting of BLS object using one scheme failed, then we need to attempt again with the opposite scheme.
|
||||
// This is due to the fact that LazyBLSWrapper receives a serialised buffer but attempts to create actual BLS object when needed.
|
||||
// That could happen when the fork has been activated and the enforced scheme has switched.
|
||||
obj.SetByteVector(vecBytes, !bufLegacyScheme);
|
||||
if (obj.IsValid()) {
|
||||
bufLegacyScheme = !bufLegacyScheme;
|
||||
}
|
||||
bufValid = false;
|
||||
return invalidObj;
|
||||
}
|
||||
if (!obj.CheckMalleable(vecBytes, bufLegacyScheme)) {
|
||||
bufValid = false;
|
||||
objInitialized = false;
|
||||
obj = invalidObj;
|
||||
} else {
|
||||
objInitialized = true;
|
||||
return invalidObj;
|
||||
}
|
||||
objInitialized = true;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -549,13 +538,16 @@ public:
|
||||
return !(*this == r);
|
||||
}
|
||||
|
||||
uint256 GetHash(const bool specificLegacyScheme = bls::bls_legacy_scheme.load()) const
|
||||
uint256 GetHash() const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mutex);
|
||||
if (!bufValid || bufLegacyScheme != specificLegacyScheme) {
|
||||
vecBytes = obj.ToByteVector(specificLegacyScheme);
|
||||
if (!objInitialized && !bufValid) {
|
||||
vecBytes.resize(BLSObject::SerSize);
|
||||
std::fill(vecBytes.begin(), vecBytes.end(), 0);
|
||||
hash.SetNull();
|
||||
} else if (!bufValid) {
|
||||
vecBytes = obj.ToByteVector(bufLegacyScheme);
|
||||
bufValid = true;
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
hash.SetNull();
|
||||
}
|
||||
if (hash.IsNull()) {
|
||||
@ -565,6 +557,21 @@ public:
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool IsLegacy() const
|
||||
{
|
||||
return bufLegacyScheme;
|
||||
}
|
||||
|
||||
void SetLegacy(bool specificLegacyScheme)
|
||||
{
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return Get().ToString(bufLegacyScheme);
|
||||
}
|
||||
};
|
||||
using CBLSLazySignature = CBLSLazyWrapper<CBLSSignature>;
|
||||
using CBLSLazyPublicKey = CBLSLazyWrapper<CBLSPublicKey>;
|
||||
|
@ -485,10 +485,10 @@ public:
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_V19].nFalloffCoeff = 5; // this corresponds to 10 periods
|
||||
|
||||
// The best chain should have at least this much work.
|
||||
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000002d68cb6c090031f"); // 864000
|
||||
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000002d68c6dc9ca04f3"); // 840000
|
||||
|
||||
// By default assume that the signatures in ancestors of this block are valid.
|
||||
consensus.defaultAssumeValid = uint256S("0x0000005c35514190ef3c38d322f69412553dc7e1107ed5f92adc2935b90acc51"); // 864000
|
||||
consensus.defaultAssumeValid = uint256S("0x000000cd7c3084499912ae893125c13e8c3c656abb6e511dcec6619c3d65a510"); // 840000
|
||||
|
||||
pchMessageStart[0] = 0xce;
|
||||
pchMessageStart[1] = 0xe2;
|
||||
@ -568,16 +568,16 @@ public:
|
||||
{470000, uint256S("0x0000009303aeadf8cf3812f5c869691dbd4cb118ad20e9bf553be434bafe6a52")},
|
||||
{794950, uint256S("0x000001860e4c7248a9c5cc3bc7106041750560dc5cd9b3a2641b49494bcff5f2")},
|
||||
{808000, uint256S("0x00000104cb60a2b5e00a8a4259582756e5bf0dca201c0993c63f0e54971ea91a")},
|
||||
{864000, uint256S("0x0000005c35514190ef3c38d322f69412553dc7e1107ed5f92adc2935b90acc51")},
|
||||
{840000, uint256S("0x000000cd7c3084499912ae893125c13e8c3c656abb6e511dcec6619c3d65a510")},
|
||||
}
|
||||
};
|
||||
|
||||
// getchaintxstats 17280 0000005c35514190ef3c38d322f69412553dc7e1107ed5f92adc2935b90acc51
|
||||
// getchaintxstats 17280 000000cd7c3084499912ae893125c13e8c3c656abb6e511dcec6619c3d65a510
|
||||
chainTxData = ChainTxData{
|
||||
1680868209, // * UNIX timestamp of last known number of transactions (Block 771537)
|
||||
5847013, // * total number of transactions between genesis and that timestamp
|
||||
1676885923, // * UNIX timestamp of last known number of transactions (Block 840000)
|
||||
5776047, // * total number of transactions between genesis and that timestamp
|
||||
// (the tx=... number in the ChainStateFlushed debug.log lines)
|
||||
0.01994632331955769, // * estimated number of transactions per second after that timestamp
|
||||
0.01120953982471268, // * estimated number of transactions per second after that timestamp
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -41,22 +41,22 @@ bool CCoinJoinEntry::AddScriptSig(const CTxIn& txin)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 CCoinJoinQueue::GetSignatureHash() const
|
||||
uint256 CCoinJoinQueue::GetSignatureHash(bool legacy) const
|
||||
{
|
||||
return SerializeHash(*this);
|
||||
int version = legacy ? COINJOIN_PROTX_HASH_PROTO_VERSION - 1 : PROTOCOL_VERSION;
|
||||
return SerializeHash(*this, SER_GETHASH, version);
|
||||
}
|
||||
|
||||
bool CCoinJoinQueue::Sign()
|
||||
{
|
||||
if (!fMasternodeMode) return false;
|
||||
|
||||
|
||||
uint256 hash = GetSignatureHash();
|
||||
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
uint256 hash = GetSignatureHash(legacy_bls_scheme);
|
||||
CBLSSignature sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(hash));
|
||||
if (!sig.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
vchSig = sig.ToByteVector(legacy_bls_scheme);
|
||||
|
||||
return true;
|
||||
@ -64,7 +64,8 @@ bool CCoinJoinQueue::Sign()
|
||||
|
||||
bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const
|
||||
{
|
||||
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash())) {
|
||||
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) {
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n");
|
||||
return false;
|
||||
}
|
||||
@ -89,21 +90,22 @@ bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const
|
||||
nTime - current_time > COINJOIN_QUEUE_TIMEOUT;
|
||||
}
|
||||
|
||||
uint256 CCoinJoinBroadcastTx::GetSignatureHash() const
|
||||
uint256 CCoinJoinBroadcastTx::GetSignatureHash(bool legacy) const
|
||||
{
|
||||
return SerializeHash(*this);
|
||||
int version = legacy ? COINJOIN_PROTX_HASH_PROTO_VERSION - 1 : PROTOCOL_VERSION;
|
||||
return SerializeHash(*this, SER_GETHASH, version);
|
||||
}
|
||||
|
||||
bool CCoinJoinBroadcastTx::Sign()
|
||||
{
|
||||
if (!fMasternodeMode) return false;
|
||||
|
||||
uint256 hash = GetSignatureHash();
|
||||
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
uint256 hash = GetSignatureHash(legacy_bls_scheme);
|
||||
CBLSSignature sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(hash));
|
||||
if (!sig.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
vchSig = sig.ToByteVector(legacy_bls_scheme);
|
||||
|
||||
return true;
|
||||
@ -111,7 +113,8 @@ bool CCoinJoinBroadcastTx::Sign()
|
||||
|
||||
bool CCoinJoinBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const
|
||||
{
|
||||
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash())) {
|
||||
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) {
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinBroadcastTx::CheckSignature -- VerifyInsecure() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ public:
|
||||
{
|
||||
READWRITE(obj.nDenom);
|
||||
|
||||
if (s.GetVersion() < COINJOIN_PROTX_HASH_PROTO_VERSION || (s.GetType() & SER_GETHASH)) {
|
||||
if (s.GetVersion() < COINJOIN_PROTX_HASH_PROTO_VERSION) {
|
||||
READWRITE(obj.masternodeOutpoint);
|
||||
} else {
|
||||
READWRITE(obj.m_protxHash);
|
||||
@ -230,7 +230,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] uint256 GetSignatureHash() const;
|
||||
[[nodiscard]] uint256 GetSignatureHash(bool legacy) const;
|
||||
/** Sign this mixing transaction
|
||||
* return true if all conditions are met:
|
||||
* 1) we have an active Masternode,
|
||||
@ -292,7 +292,7 @@ public:
|
||||
{
|
||||
READWRITE(obj.tx);
|
||||
|
||||
if (s.GetVersion() < COINJOIN_PROTX_HASH_PROTO_VERSION || (s.GetType() & SER_GETHASH)) {
|
||||
if (s.GetVersion() < COINJOIN_PROTX_HASH_PROTO_VERSION) {
|
||||
READWRITE(obj.masternodeOutpoint);
|
||||
} else {
|
||||
READWRITE(obj.m_protxHash);
|
||||
@ -317,7 +317,7 @@ public:
|
||||
return *this != CCoinJoinBroadcastTx();
|
||||
}
|
||||
|
||||
[[nodiscard]] uint256 GetSignatureHash() const;
|
||||
[[nodiscard]] uint256 GetSignatureHash(bool legacy) const;
|
||||
|
||||
bool Sign();
|
||||
[[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const;
|
||||
|
@ -121,8 +121,7 @@ bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev
|
||||
int64_t nTime2 = GetTimeMicros(); nTimeDMN += nTime2 - nTime1;
|
||||
LogPrint(BCLog::BENCHMARK, " - BuildNewListFromBlock: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeDMN * 0.000001);
|
||||
|
||||
bool v19active = llmq::utils::IsV19Active(pindexPrev);
|
||||
CSimplifiedMNList sml(tmpMNList, v19active);
|
||||
CSimplifiedMNList sml(tmpMNList);
|
||||
|
||||
int64_t nTime3 = GetTimeMicros(); nTimeSMNL += nTime3 - nTime2;
|
||||
LogPrint(BCLog::BENCHMARK, " - CSimplifiedMNList: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeSMNL * 0.000001);
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const std::string DB_LIST_SNAPSHOT = "dmn_S2";
|
||||
static const std::string DB_LIST_DIFF = "dmn_D2";
|
||||
static const std::string DB_LIST_SNAPSHOT = "dmn_S3";
|
||||
static const std::string DB_LIST_DIFF = "dmn_D3";
|
||||
|
||||
std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
|
||||
|
||||
@ -405,23 +405,18 @@ CDeterministicMNListDiff CDeterministicMNList::BuildDiff(const CDeterministicMNL
|
||||
|
||||
CSimplifiedMNListDiff CDeterministicMNList::BuildSimplifiedDiff(const CDeterministicMNList& to, bool extended) const
|
||||
{
|
||||
bool v19active = llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
CSimplifiedMNListDiff diffRet;
|
||||
diffRet.baseBlockHash = blockHash;
|
||||
diffRet.blockHash = to.blockHash;
|
||||
diffRet.nVersion = v19active ? CSimplifiedMNListDiff::BASIC_BLS_VERSION : CSimplifiedMNListDiff::LEGACY_BLS_VERSION;
|
||||
|
||||
to.ForEachMN(false, [&](const auto& toPtr) {
|
||||
auto fromPtr = GetMN(toPtr.proTxHash);
|
||||
if (fromPtr == nullptr) {
|
||||
CSimplifiedMNListEntry sme(toPtr);
|
||||
sme.nVersion = diffRet.nVersion;
|
||||
diffRet.mnList.push_back(std::move(sme));
|
||||
} else {
|
||||
CSimplifiedMNListEntry sme1(toPtr);
|
||||
CSimplifiedMNListEntry sme2(*fromPtr);
|
||||
sme1.nVersion = diffRet.nVersion;
|
||||
sme2.nVersion = diffRet.nVersion;
|
||||
if ((sme1 != sme2) ||
|
||||
(extended && (sme1.scriptPayout != sme2.scriptPayout || sme1.scriptOperatorPayout != sme2.scriptOperatorPayout))) {
|
||||
diffRet.mnList.push_back(std::move(sme1));
|
||||
@ -463,48 +458,6 @@ CDeterministicMNList CDeterministicMNList::ApplyDiff(const CBlockIndex* pindex,
|
||||
return result;
|
||||
}
|
||||
|
||||
// RepopulateUniquePropertyMap clears internal mnUniquePropertyMap, and repopulate it with currently MNs unique properties.
|
||||
// This is needed when the v19 fork activates, we need to store again pubKeyOperator in the mnUniquePropertyMap.
|
||||
// pubKeyOperator don't differ between the two schemes (legacy and basic(v19)) but their serialisation do: hence their hash.
|
||||
// And because mnUniquePropertyMap store only hashes, then we need to re-calculate hashes and repopulate.
|
||||
void CDeterministicMNList::RepopulateUniquePropertyMap() {
|
||||
decltype(mnUniquePropertyMap) mnUniquePropertyMapEmpty;
|
||||
mnUniquePropertyMap = mnUniquePropertyMapEmpty;
|
||||
|
||||
for (const auto &p: mnMap) {
|
||||
auto dmn = p.second;
|
||||
if (!AddUniqueProperty(*dmn, dmn->collateralOutpoint)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate collateralOutpoint=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort())));
|
||||
}
|
||||
if (dmn->pdmnState->addr != CService() && !AddUniqueProperty(*dmn, dmn->pdmnState->addr)) {
|
||||
throw (std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s", __func__,
|
||||
dmn->proTxHash.ToString(),
|
||||
dmn->pdmnState->addr.ToStringIPPort(false))));
|
||||
}
|
||||
if (!AddUniqueProperty(*dmn, dmn->pdmnState->keyIDOwner)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate keyIDOwner=%s", __func__,
|
||||
dmn->proTxHash.ToString(), EncodeDestination(PKHash(dmn->pdmnState->keyIDOwner)))));
|
||||
}
|
||||
if (dmn->pdmnState->pubKeyOperator.Get().IsValid() &&
|
||||
!AddUniqueProperty(*dmn, dmn->pdmnState->pubKeyOperator)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate pubKeyOperator=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.Get().ToString())));
|
||||
}
|
||||
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
if (!AddUniqueProperty(*dmn, dmn->pdmnState->platformNodeID)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate platformNodeID=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->platformNodeID.ToString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount)
|
||||
{
|
||||
assert(dmn != nullptr);
|
||||
@ -538,7 +491,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
|
||||
if (dmn->pdmnState->pubKeyOperator.Get().IsValid() && !AddUniqueProperty(*dmn, dmn->pdmnState->pubKeyOperator)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate pubKeyOperator=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.Get().ToString())));
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.ToString())));
|
||||
}
|
||||
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
@ -561,7 +514,6 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
|
||||
{
|
||||
auto dmn = std::make_shared<CDeterministicMN>(oldDmn);
|
||||
auto oldState = dmn->pdmnState;
|
||||
dmn->pdmnState = pdmnState;
|
||||
|
||||
// All mnUniquePropertyMap's updates must be atomic.
|
||||
// Using this temporary map as a checkpoint to roll back to in case of any issues.
|
||||
@ -580,16 +532,17 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
|
||||
if (!UpdateUniqueProperty(*dmn, oldState->pubKeyOperator, pdmnState->pubKeyOperator)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't update a masternode %s with a duplicate pubKeyOperator=%s", __func__,
|
||||
oldDmn.proTxHash.ToString(), pdmnState->pubKeyOperator.Get().ToString())));
|
||||
oldDmn.proTxHash.ToString(), pdmnState->pubKeyOperator.ToString())));
|
||||
}
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
if (!UpdateUniqueProperty(*dmn, oldState->platformNodeID, dmn->pdmnState->platformNodeID)) {
|
||||
if (!UpdateUniqueProperty(*dmn, oldState->platformNodeID, pdmnState->platformNodeID)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't update a masternode %s with a duplicate platformNodeID=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->platformNodeID.ToString())));
|
||||
oldDmn.proTxHash.ToString(), pdmnState->platformNodeID.ToString())));
|
||||
}
|
||||
}
|
||||
|
||||
dmn->pdmnState = pdmnState;
|
||||
mnMap = mnMap.set(oldDmn.proTxHash, dmn);
|
||||
}
|
||||
|
||||
@ -639,7 +592,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
|
||||
if (dmn->pdmnState->pubKeyOperator.Get().IsValid() && !DeleteUniqueProperty(*dmn, dmn->pdmnState->pubKeyOperator)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't delete a masternode %s with a pubKeyOperator=%s", __func__,
|
||||
proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.Get().ToString())));
|
||||
proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.ToString())));
|
||||
}
|
||||
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
@ -687,19 +640,11 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
||||
|
||||
newList.SetBlockHash(block.GetHash());
|
||||
|
||||
// If the fork is active for pindex block, then we need to repopulate property map
|
||||
// (Check documentation of CDeterministicMNList::RepopulateUniquePropertyMap()).
|
||||
// This is needed only when base list is pre-v19 fork and pindex is post-v19 fork.
|
||||
bool v19_just_activated = pindex == llmq::utils::V19ActivationIndex(pindex);
|
||||
if (v19_just_activated) {
|
||||
newList.RepopulateUniquePropertyMap();
|
||||
}
|
||||
|
||||
oldList = GetListForBlock(pindex->pprev);
|
||||
diff = oldList.BuildDiff(newList);
|
||||
|
||||
m_evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff);
|
||||
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1 || v19_just_activated) {
|
||||
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1) {
|
||||
m_evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList);
|
||||
mnListsCache.emplace(newList.GetBlockHash(), newList);
|
||||
LogPrintf("CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n",
|
||||
@ -940,12 +885,14 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
||||
}
|
||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||
if (newState->pubKeyOperator != proTx.pubKeyOperator) {
|
||||
// reset all operator related fields and put MN into PoSe-banned state in case the operator key changes
|
||||
newState->ResetOperatorFields();
|
||||
newState->BanIfNotBanned(nHeight);
|
||||
// we update pubKeyOperator here, make sure state version matches
|
||||
newState->nVersion = proTx.nVersion;
|
||||
newState->pubKeyOperator = proTx.pubKeyOperator;
|
||||
}
|
||||
newState->pubKeyOperator.Set(proTx.pubKeyOperator);
|
||||
newState->keyIDVoting = proTx.keyIDVoting;
|
||||
newState->scriptPayout = proTx.scriptPayout;
|
||||
|
||||
@ -1228,9 +1175,14 @@ void CDeterministicMNManager::CleanupCache(int nHeight)
|
||||
std::vector<uint256> toDeleteDiffs;
|
||||
for (const auto& p : mnListsCache) {
|
||||
if (p.second.GetHeight() + LIST_DIFFS_CACHE_SIZE < nHeight) {
|
||||
// too old, drop it
|
||||
toDeleteLists.emplace_back(p.first);
|
||||
continue;
|
||||
}
|
||||
if (tipIndex != nullptr && p.first == tipIndex->GetBlockHash()) {
|
||||
// it's a snapshot for the tip, keep it
|
||||
continue;
|
||||
}
|
||||
bool fQuorumCache = ranges::any_of(Params().GetConsensus().llmqs, [&nHeight, &p](const auto& params){
|
||||
return (p.second.GetHeight() % params.dkgInterval == 0) &&
|
||||
(p.second.GetHeight() + params.dkgInterval * (params.keepOldConnections + 1) >= nHeight);
|
||||
@ -1239,13 +1191,8 @@ void CDeterministicMNManager::CleanupCache(int nHeight)
|
||||
// at least one quorum could be using it, keep it
|
||||
continue;
|
||||
}
|
||||
// no alive quorums using it, see if it was a cache for the tip or for a now outdated quorum
|
||||
if (tipIndex && tipIndex->pprev && (p.first == tipIndex->pprev->GetBlockHash())) {
|
||||
toDeleteLists.emplace_back(p.first);
|
||||
} else if (ranges::any_of(Params().GetConsensus().llmqs,
|
||||
[&p](const auto& llmqParams){ return p.second.GetHeight() % llmqParams.dkgInterval == 0; })) {
|
||||
toDeleteLists.emplace_back(p.first);
|
||||
}
|
||||
// none of the above, drop it
|
||||
toDeleteLists.emplace_back(p.first);
|
||||
}
|
||||
for (const auto& h : toDeleteLists) {
|
||||
mnListsCache.erase(h);
|
||||
@ -1266,6 +1213,7 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
static const std::string DB_OLD_LIST_SNAPSHOT = "dmn_S";
|
||||
static const std::string DB_OLD_LIST_DIFF = "dmn_D";
|
||||
static const std::string DB_OLD_BEST_BLOCK = "b_b2";
|
||||
static const std::string DB_OLD_BEST_BLOCK2 = "b_b3";
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
@ -1277,11 +1225,17 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
return m_evoDb.IsEmpty();
|
||||
}
|
||||
|
||||
if (m_evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK)) {
|
||||
if (m_evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK) || m_evoDb.GetRawDB().Exists(DB_OLD_BEST_BLOCK2)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration already done. skipping.\n", __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (::ChainActive().Tip()->pprev != nullptr && llmq::utils::IsV19Active(::ChainActive().Tip()->pprev)) {
|
||||
// too late
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -1304,15 +1258,15 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
|
||||
for (const auto nHeight : irange::range(Params().GetConsensus().DIP0003Height, ::ChainActive().Height() + 1)) {
|
||||
auto pindex = ::ChainActive()[nHeight];
|
||||
// Unserialise CDeterministicMNListDiff using CURRENT_MN_FORMAT and set it's type to the default value TYPE_REGULAR_MASTERNODE
|
||||
// It will be later written with format MN_TYPE_FORMAT which includes the type field.
|
||||
// Unserialise CDeterministicMNListDiff using MN_OLD_FORMAT and set it's type to the default value TYPE_REGULAR_MASTERNODE
|
||||
// It will be later written with format MN_CURRENT_FORMAT which includes the type field and MN state bls version.
|
||||
CDataStream diff_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_DIFF, pindex->GetBlockHash()), diff_data)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- missing CDeterministicMNListDiff at height %d\n", __func__, nHeight);
|
||||
return false;
|
||||
}
|
||||
CDeterministicMNListDiff mndiff;
|
||||
mndiff.Unserialize(diff_data, CDeterministicMN::CURRENT_MN_FORMAT);
|
||||
mndiff.Unserialize(diff_data, CDeterministicMN::MN_OLD_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), mndiff);
|
||||
CDataStream snapshot_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot_data)) {
|
||||
@ -1320,7 +1274,7 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
continue;
|
||||
}
|
||||
CDeterministicMNList mnList;
|
||||
mnList.Unserialize(snapshot_data, CDeterministicMN::CURRENT_MN_FORMAT);
|
||||
mnList.Unserialize(snapshot_data, CDeterministicMN::MN_OLD_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), mnList);
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
batch.Clear();
|
||||
@ -1329,7 +1283,7 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
|
||||
// Writing EVODB_BEST_BLOCK (which is b_b3 now) marks the DB as upgraded
|
||||
// Writing EVODB_BEST_BLOCK (which is b_b4 now) marks the DB as upgraded
|
||||
auto dbTx = m_evoDb.BeginTransaction();
|
||||
m_evoDb.WriteBestBlock(::ChainActive().Tip()->GetBlockHash());
|
||||
dbTx->Commit();
|
||||
@ -1345,6 +1299,111 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done compacting database\n", __func__);
|
||||
|
||||
// flush it to disk
|
||||
if (!m_evoDb.CommitRootTransaction()) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- failed to commit to evoDB\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDeterministicMNManager::MigrateDBIfNeeded2()
|
||||
{
|
||||
static const std::string DB_OLD_LIST_SNAPSHOT = "dmn_S2";
|
||||
static const std::string DB_OLD_LIST_DIFF = "dmn_D2";
|
||||
static const std::string DB_OLD_BEST_BLOCK = "b_b3";
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- upgrading DB to migrate MN state bls version\n", __func__);
|
||||
|
||||
if (::ChainActive().Tip() == nullptr) {
|
||||
// should have no records
|
||||
LogPrintf("CDeterministicMNManager::%s -- Chain empty. evoDB:%d.\n", __func__, m_evoDb.IsEmpty());
|
||||
return m_evoDb.IsEmpty();
|
||||
}
|
||||
|
||||
if (m_evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration already done. skipping.\n", __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (::ChainActive().Tip()->pprev != nullptr && llmq::utils::IsV19Active(::ChainActive().Tip()->pprev)) {
|
||||
// too late
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 && !m_evoDb.GetRawDB().Exists(DB_OLD_BEST_BLOCK)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- previous migration attempt failed.\n", __func__);
|
||||
return false;
|
||||
}
|
||||
m_evoDb.GetRawDB().Erase(DB_OLD_BEST_BLOCK);
|
||||
|
||||
if (::ChainActive().Height() < Params().GetConsensus().DIP0003Height) {
|
||||
// not reached DIP3 height yet, so no upgrade needed
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration not needed. dip3 not reached\n", __func__);
|
||||
auto dbTx = m_evoDb.BeginTransaction();
|
||||
m_evoDb.WriteBestBlock(::ChainActive().Tip()->GetBlockHash());
|
||||
dbTx->Commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
CDBBatch batch(m_evoDb.GetRawDB());
|
||||
|
||||
for (const auto nHeight : irange::range(Params().GetConsensus().DIP0003Height, ::ChainActive().Height() + 1)) {
|
||||
auto pindex = ::ChainActive()[nHeight];
|
||||
// Unserialise CDeterministicMNListDiff using MN_TYPE_FORMAT and set MN state bls version to LEGACY_BLS_VERSION.
|
||||
// It will be later written with format MN_CURRENT_FORMAT which includes the type field.
|
||||
CDataStream diff_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_DIFF, pindex->GetBlockHash()), diff_data)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- missing CDeterministicMNListDiff at height %d\n", __func__, nHeight);
|
||||
return false;
|
||||
}
|
||||
CDeterministicMNListDiff mndiff;
|
||||
mndiff.Unserialize(diff_data, CDeterministicMN::MN_TYPE_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), mndiff);
|
||||
CDataStream snapshot_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot_data)) {
|
||||
// it's ok, we write snapshots every DISK_SNAPSHOT_PERIOD blocks only
|
||||
continue;
|
||||
}
|
||||
CDeterministicMNList mnList;
|
||||
mnList.Unserialize(snapshot_data, CDeterministicMN::MN_TYPE_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), mnList);
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
batch.Clear();
|
||||
LogPrintf("CDeterministicMNManager::%s -- wrote snapshot at height %d\n", __func__, nHeight);
|
||||
}
|
||||
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
|
||||
// Writing EVODB_BEST_BLOCK (which is b_b4 now) marks the DB as upgraded
|
||||
auto dbTx = m_evoDb.BeginTransaction();
|
||||
m_evoDb.WriteBestBlock(::ChainActive().Tip()->GetBlockHash());
|
||||
dbTx->Commit();
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done migrating\n", __func__);
|
||||
|
||||
m_evoDb.GetRawDB().Erase(DB_OLD_LIST_DIFF);
|
||||
m_evoDb.GetRawDB().Erase(DB_OLD_LIST_SNAPSHOT);
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done cleaning old data\n", __func__);
|
||||
|
||||
m_evoDb.GetRawDB().CompactFull();
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done compacting database\n", __func__);
|
||||
|
||||
// flush it to disk
|
||||
if (!m_evoDb.CommitRootTransaction()) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- failed to commit to evoDB\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,10 @@ private:
|
||||
uint64_t internalId{std::numeric_limits<uint64_t>::max()};
|
||||
|
||||
public:
|
||||
static constexpr uint16_t CURRENT_MN_FORMAT = 0;
|
||||
static constexpr uint16_t MN_OLD_FORMAT = 0;
|
||||
static constexpr uint16_t MN_TYPE_FORMAT = 1;
|
||||
static constexpr uint16_t MN_VERSION_FORMAT = 2;
|
||||
static constexpr uint16_t MN_CURRENT_FORMAT = MN_VERSION_FORMAT;
|
||||
|
||||
CDeterministicMN() = delete; // no default constructor, must specify internalId
|
||||
explicit CDeterministicMN(uint64_t _internalId, MnType mnType = MnType::Regular) :
|
||||
@ -74,12 +76,16 @@ public:
|
||||
READWRITE(VARINT(internalId));
|
||||
READWRITE(collateralOutpoint);
|
||||
READWRITE(nOperatorReward);
|
||||
// We need to read CDeterministicMNState using the old format only when called with CURRENT_MN_FORMAT on Unserialize()
|
||||
// We need to read CDeterministicMNState using the old format only when called with MN_OLD_FORMAT or MN_TYPE_FORMAT on Unserialize()
|
||||
// Serialisation (writing) will be done always using new format
|
||||
if (ser_action.ForRead() && format_version == CURRENT_MN_FORMAT) {
|
||||
if (ser_action.ForRead() && format_version == MN_OLD_FORMAT) {
|
||||
CDeterministicMNState_Oldformat old_state;
|
||||
READWRITE(old_state);
|
||||
pdmnState = std::make_shared<const CDeterministicMNState>(old_state);
|
||||
} else if (ser_action.ForRead() && format_version == MN_TYPE_FORMAT) {
|
||||
CDeterministicMNState_mntype_format old_state;
|
||||
READWRITE(old_state);
|
||||
pdmnState = std::make_shared<const CDeterministicMNState>(old_state);
|
||||
} else {
|
||||
READWRITE(pdmnState);
|
||||
}
|
||||
@ -98,11 +104,11 @@ public:
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
const_cast<CDeterministicMN*>(this)->SerializationOp(s, CSerActionSerialize(), MN_TYPE_FORMAT);
|
||||
const_cast<CDeterministicMN*>(this)->SerializationOp(s, CSerActionSerialize(), MN_CURRENT_FORMAT);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s, const uint8_t format_version = MN_TYPE_FORMAT)
|
||||
void Unserialize(Stream& s, const uint8_t format_version = MN_CURRENT_FORMAT)
|
||||
{
|
||||
SerializationOp(s, CSerActionUnserialize(), format_version);
|
||||
}
|
||||
@ -204,14 +210,14 @@ public:
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_TYPE_FORMAT) {
|
||||
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_CURRENT_FORMAT) {
|
||||
mnMap = MnMap();
|
||||
mnUniquePropertyMap = MnUniquePropertyMap();
|
||||
mnInternalIdMap = MnInternalIdMap();
|
||||
|
||||
SerializationOpBase(s, CSerActionUnserialize());
|
||||
|
||||
bool evodb_migration = (format_version == CDeterministicMN::CURRENT_MN_FORMAT);
|
||||
bool evodb_migration = (format_version == CDeterministicMN::MN_OLD_FORMAT || format_version == CDeterministicMN::MN_TYPE_FORMAT);
|
||||
size_t cnt = ReadCompactSize(s);
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
if (evodb_migration) {
|
||||
@ -385,8 +391,6 @@ public:
|
||||
[[nodiscard]] CSimplifiedMNListDiff BuildSimplifiedDiff(const CDeterministicMNList& to, bool extended) const;
|
||||
[[nodiscard]] CDeterministicMNList ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const;
|
||||
|
||||
void RepopulateUniquePropertyMap();
|
||||
|
||||
void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true);
|
||||
void UpdateMN(const CDeterministicMN& oldDmn, const std::shared_ptr<const CDeterministicMNState>& pdmnState);
|
||||
void UpdateMN(const uint256& proTxHash, const std::shared_ptr<const CDeterministicMNState>& pdmnState);
|
||||
@ -396,12 +400,12 @@ public:
|
||||
template <typename T>
|
||||
[[nodiscard]] bool HasUniqueProperty(const T& v) const
|
||||
{
|
||||
return mnUniquePropertyMap.count(::SerializeHash(v)) != 0;
|
||||
return mnUniquePropertyMap.count(GetUniquePropertyHash(v)) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] CDeterministicMNCPtr GetUniquePropertyMN(const T& v) const
|
||||
{
|
||||
auto p = mnUniquePropertyMap.find(::SerializeHash(v));
|
||||
auto p = mnUniquePropertyMap.find(GetUniquePropertyHash(v));
|
||||
if (!p) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -409,6 +413,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
[[nodiscard]] uint256 GetUniquePropertyHash(const T& v) const
|
||||
{
|
||||
if constexpr (std::is_same<T, CBLSPublicKey>()) {
|
||||
assert(false);
|
||||
}
|
||||
return ::SerializeHash(v);
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] bool AddUniqueProperty(const CDeterministicMN& dmn, const T& v)
|
||||
{
|
||||
@ -417,7 +429,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto hash = ::SerializeHash(v);
|
||||
auto hash = GetUniquePropertyHash(v);
|
||||
auto oldEntry = mnUniquePropertyMap.find(hash);
|
||||
if (oldEntry != nullptr && oldEntry->first != dmn.proTxHash) {
|
||||
return false;
|
||||
@ -437,7 +449,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto oldHash = ::SerializeHash(oldValue);
|
||||
auto oldHash = GetUniquePropertyHash(oldValue);
|
||||
auto p = mnUniquePropertyMap.find(oldHash);
|
||||
if (p == nullptr || p->first != dmn.proTxHash) {
|
||||
return false;
|
||||
@ -466,6 +478,16 @@ private:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool operator==(const CDeterministicMNList& a, const CDeterministicMNList& b)
|
||||
{
|
||||
return a.blockHash == b.blockHash &&
|
||||
a.nHeight == b.nHeight &&
|
||||
a.nTotalRegisteredCount == b.nTotalRegisteredCount &&
|
||||
a.mnMap == b.mnMap &&
|
||||
a.mnInternalIdMap == b.mnInternalIdMap &&
|
||||
a.mnUniquePropertyMap == b.mnUniquePropertyMap;
|
||||
}
|
||||
};
|
||||
|
||||
class CDeterministicMNListDiff
|
||||
@ -494,7 +516,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_TYPE_FORMAT)
|
||||
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_CURRENT_FORMAT)
|
||||
{
|
||||
updatedMNs.clear();
|
||||
removedMns.clear();
|
||||
@ -504,8 +526,6 @@ public:
|
||||
tmp = ReadCompactSize(s);
|
||||
for (size_t i = 0; i < tmp; i++) {
|
||||
CDeterministicMN mn(0);
|
||||
// Unserialise CDeterministicMN using CURRENT_MN_FORMAT and set it's type to the default value TYPE_REGULAR_MASTERNODE
|
||||
// It will be later written with format MN_TYPE_FORMAT which includes the type field.
|
||||
mn.Unserialize(s, format_version);
|
||||
auto dmn = std::make_shared<CDeterministicMN>(mn);
|
||||
addedMNs.push_back(dmn);
|
||||
@ -534,10 +554,20 @@ public:
|
||||
};
|
||||
|
||||
|
||||
constexpr int llmq_max_blocks() {
|
||||
int max_blocks{0};
|
||||
for (const auto& llmq : Consensus::available_llmqs) {
|
||||
int blocks = (llmq.useRotation ? 1 : llmq.signingActiveQuorumCount) * llmq.dkgInterval;
|
||||
max_blocks = std::max(max_blocks, blocks);
|
||||
}
|
||||
return max_blocks;
|
||||
}
|
||||
|
||||
class CDeterministicMNManager
|
||||
{
|
||||
static constexpr int DISK_SNAPSHOT_PERIOD = 576; // once per day
|
||||
static constexpr int DISK_SNAPSHOTS = 3; // keep cache for 3 disk snapshots to have 2 full days covered
|
||||
// keep cache for enough disk snapshots to have all active quourms covered
|
||||
static constexpr int DISK_SNAPSHOTS = llmq_max_blocks() / DISK_SNAPSHOT_PERIOD + 1;
|
||||
static constexpr int LIST_DIFFS_CACHE_SIZE = DISK_SNAPSHOT_PERIOD * DISK_SNAPSHOTS;
|
||||
|
||||
public:
|
||||
@ -584,6 +614,7 @@ public:
|
||||
bool IsDIP3Enforced(int nHeight = -1);
|
||||
|
||||
bool MigrateDBIfNeeded();
|
||||
bool MigrateDBIfNeeded2();
|
||||
|
||||
void DoMaintenance();
|
||||
|
||||
|
@ -26,16 +26,17 @@ std::string CDeterministicMNState::ToString() const
|
||||
operatorPayoutAddress = EncodeDestination(dest);
|
||||
}
|
||||
|
||||
return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, "
|
||||
return strprintf("CDeterministicMNState(nVersion=%d, nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, "
|
||||
"ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
|
||||
nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason,
|
||||
EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.Get().ToString(), EncodeDestination(PKHash(keyIDVoting)), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
|
||||
nVersion, nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason,
|
||||
EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
|
||||
}
|
||||
|
||||
void CDeterministicMNState::ToJson(UniValue& obj, MnType nType) const
|
||||
{
|
||||
obj.clear();
|
||||
obj.setObject();
|
||||
obj.pushKV("version", nVersion);
|
||||
obj.pushKV("service", addr.ToStringIPPort(false));
|
||||
obj.pushKV("registeredHeight", nRegisteredHeight);
|
||||
obj.pushKV("lastPaidHeight", nLastPaidHeight);
|
||||
@ -56,7 +57,7 @@ void CDeterministicMNState::ToJson(UniValue& obj, MnType nType) const
|
||||
if (ExtractDestination(scriptPayout, dest)) {
|
||||
obj.pushKV("payoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.Get().ToString());
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
|
||||
if (ExtractDestination(scriptOperatorPayout, dest)) {
|
||||
obj.pushKV("operatorPayoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
|
@ -72,6 +72,62 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: To remove this in the future
|
||||
class CDeterministicMNState_mntype_format
|
||||
{
|
||||
private:
|
||||
int nPoSeBanHeight{-1};
|
||||
|
||||
friend class CDeterministicMNStateDiff;
|
||||
friend class CDeterministicMNState;
|
||||
|
||||
public:
|
||||
int nRegisteredHeight{-1};
|
||||
int nLastPaidHeight{0};
|
||||
int nConsecutivePayments{0};
|
||||
int nPoSePenalty{0};
|
||||
int nPoSeRevivedHeight{-1};
|
||||
uint16_t nRevocationReason{CProUpRevTx::REASON_NOT_SPECIFIED};
|
||||
uint256 confirmedHash;
|
||||
uint256 confirmedHashWithProRegTxHash;
|
||||
CKeyID keyIDOwner;
|
||||
CBLSLazyPublicKey pubKeyOperator;
|
||||
CKeyID keyIDVoting;
|
||||
CService addr;
|
||||
CScript scriptPayout;
|
||||
CScript scriptOperatorPayout;
|
||||
|
||||
uint160 platformNodeID{};
|
||||
uint16_t platformP2PPort{0};
|
||||
uint16_t platformHTTPPort{0};
|
||||
|
||||
public:
|
||||
CDeterministicMNState_mntype_format() = default;
|
||||
|
||||
SERIALIZE_METHODS(CDeterministicMNState_mntype_format, obj)
|
||||
{
|
||||
READWRITE(
|
||||
obj.nRegisteredHeight,
|
||||
obj.nLastPaidHeight,
|
||||
obj.nConsecutivePayments,
|
||||
obj.nPoSePenalty,
|
||||
obj.nPoSeRevivedHeight,
|
||||
obj.nPoSeBanHeight,
|
||||
obj.nRevocationReason,
|
||||
obj.confirmedHash,
|
||||
obj.confirmedHashWithProRegTxHash,
|
||||
obj.keyIDOwner,
|
||||
obj.pubKeyOperator,
|
||||
obj.keyIDVoting,
|
||||
obj.addr,
|
||||
obj.scriptPayout,
|
||||
obj.scriptOperatorPayout,
|
||||
obj.platformNodeID,
|
||||
obj.platformP2PPort,
|
||||
obj.platformHTTPPort);
|
||||
}
|
||||
};
|
||||
|
||||
class CDeterministicMNState
|
||||
{
|
||||
private:
|
||||
@ -80,6 +136,8 @@ private:
|
||||
friend class CDeterministicMNStateDiff;
|
||||
|
||||
public:
|
||||
int nVersion{CProRegTx::LEGACY_BLS_VERSION};
|
||||
|
||||
int nRegisteredHeight{-1};
|
||||
int nLastPaidHeight{0};
|
||||
int nConsecutivePayments{0};
|
||||
@ -107,7 +165,9 @@ public:
|
||||
public:
|
||||
CDeterministicMNState() = default;
|
||||
explicit CDeterministicMNState(const CProRegTx& proTx) :
|
||||
nVersion(proTx.nVersion),
|
||||
keyIDOwner(proTx.keyIDOwner),
|
||||
pubKeyOperator(proTx.pubKeyOperator),
|
||||
keyIDVoting(proTx.keyIDVoting),
|
||||
addr(proTx.addr),
|
||||
scriptPayout(proTx.scriptPayout),
|
||||
@ -115,7 +175,6 @@ public:
|
||||
platformP2PPort(proTx.platformP2PPort),
|
||||
platformHTTPPort(proTx.platformHTTPPort)
|
||||
{
|
||||
pubKeyOperator.Set(proTx.pubKeyOperator);
|
||||
}
|
||||
explicit CDeterministicMNState(const CDeterministicMNState_Oldformat& s) :
|
||||
nPoSeBanHeight(s.nPoSeBanHeight),
|
||||
@ -132,6 +191,27 @@ public:
|
||||
addr(s.addr),
|
||||
scriptPayout(s.scriptPayout),
|
||||
scriptOperatorPayout(s.scriptOperatorPayout) {}
|
||||
|
||||
explicit CDeterministicMNState(const CDeterministicMNState_mntype_format& s) :
|
||||
nPoSeBanHeight(s.nPoSeBanHeight),
|
||||
nRegisteredHeight(s.nRegisteredHeight),
|
||||
nLastPaidHeight(s.nLastPaidHeight),
|
||||
nConsecutivePayments(s.nConsecutivePayments),
|
||||
nPoSePenalty(s.nPoSePenalty),
|
||||
nPoSeRevivedHeight(s.nPoSeRevivedHeight),
|
||||
nRevocationReason(s.nRevocationReason),
|
||||
confirmedHash(s.confirmedHash),
|
||||
confirmedHashWithProRegTxHash(s.confirmedHashWithProRegTxHash),
|
||||
keyIDOwner(s.keyIDOwner),
|
||||
pubKeyOperator(s.pubKeyOperator),
|
||||
keyIDVoting(s.keyIDVoting),
|
||||
addr(s.addr),
|
||||
scriptPayout(s.scriptPayout),
|
||||
scriptOperatorPayout(s.scriptOperatorPayout),
|
||||
platformNodeID(s.platformNodeID),
|
||||
platformP2PPort(s.platformP2PPort),
|
||||
platformHTTPPort(s.platformHTTPPort) {}
|
||||
|
||||
template <typename Stream>
|
||||
CDeterministicMNState(deserialize_type, Stream& s)
|
||||
{
|
||||
@ -141,6 +221,7 @@ public:
|
||||
SERIALIZE_METHODS(CDeterministicMNState, obj)
|
||||
{
|
||||
READWRITE(
|
||||
obj.nVersion,
|
||||
obj.nRegisteredHeight,
|
||||
obj.nLastPaidHeight,
|
||||
obj.nConsecutivePayments,
|
||||
@ -150,8 +231,9 @@ public:
|
||||
obj.nRevocationReason,
|
||||
obj.confirmedHash,
|
||||
obj.confirmedHashWithProRegTxHash,
|
||||
obj.keyIDOwner,
|
||||
obj.pubKeyOperator,
|
||||
obj.keyIDOwner);
|
||||
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), obj.nVersion == CProRegTx::LEGACY_BLS_VERSION));
|
||||
READWRITE(
|
||||
obj.keyIDVoting,
|
||||
obj.addr,
|
||||
obj.scriptPayout,
|
||||
@ -163,7 +245,8 @@ public:
|
||||
|
||||
void ResetOperatorFields()
|
||||
{
|
||||
pubKeyOperator.Set(CBLSPublicKey());
|
||||
nVersion = CProRegTx::LEGACY_BLS_VERSION;
|
||||
pubKeyOperator = CBLSLazyPublicKey();
|
||||
addr = CService();
|
||||
scriptOperatorPayout = CScript();
|
||||
nRevocationReason = CProUpRevTx::REASON_NOT_SPECIFIED;
|
||||
@ -225,6 +308,7 @@ public:
|
||||
Field_platformNodeID = 0x8000,
|
||||
Field_platformP2PPort = 0x10000,
|
||||
Field_platformHTTPPort = 0x20000,
|
||||
Field_nVersion = 0x40000,
|
||||
};
|
||||
|
||||
#define DMN_STATE_DIFF_ALL_FIELDS \
|
||||
@ -245,7 +329,8 @@ public:
|
||||
DMN_STATE_DIFF_LINE(nConsecutivePayments) \
|
||||
DMN_STATE_DIFF_LINE(platformNodeID) \
|
||||
DMN_STATE_DIFF_LINE(platformP2PPort) \
|
||||
DMN_STATE_DIFF_LINE(platformHTTPPort)
|
||||
DMN_STATE_DIFF_LINE(platformHTTPPort) \
|
||||
DMN_STATE_DIFF_LINE(nVersion)
|
||||
|
||||
public:
|
||||
uint32_t fields{0};
|
||||
@ -259,19 +344,26 @@ public:
|
||||
#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
|
||||
if (fields & Field_pubKeyOperator) { state.nVersion = b.nVersion; fields |= Field_nVersion; }
|
||||
}
|
||||
|
||||
SERIALIZE_METHODS(CDeterministicMNStateDiff, obj)
|
||||
{
|
||||
// NOTE: reading pubKeyOperator requires nVersion
|
||||
bool read_pubkey{false};
|
||||
READWRITE(VARINT(obj.fields));
|
||||
#define DMN_STATE_DIFF_LINE(f) \
|
||||
if (strcmp(#f, "pubKeyOperator") == 0 && (obj.fields & Field_pubKeyOperator)) {\
|
||||
/* TODO: implement migration to Basic BLS after the fork */ \
|
||||
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.state.pubKeyOperator), true)); \
|
||||
SER_READ(obj, read_pubkey = true); \
|
||||
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.state.pubKeyOperator), obj.state.nVersion == CProRegTx::LEGACY_BLS_VERSION)); \
|
||||
} else if (obj.fields & Field_##f) READWRITE(obj.state.f);
|
||||
|
||||
DMN_STATE_DIFF_ALL_FIELDS
|
||||
#undef DMN_STATE_DIFF_LINE
|
||||
if (read_pubkey) {
|
||||
SER_READ(obj, obj.fields |= Field_nVersion);
|
||||
SER_READ(obj, obj.state.pubKeyOperator.SetLegacy(obj.state.nVersion == CProRegTx::LEGACY_BLS_VERSION));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyToState(CDeterministicMNState& target) const
|
||||
|
@ -12,7 +12,8 @@
|
||||
// "b_b" was used in the initial version of deterministic MN storage
|
||||
// "b_b2" was used after compact diffs were introduced
|
||||
// "b_b3" was used after masternode type introduction in evoDB
|
||||
static const std::string EVODB_BEST_BLOCK = "b_b3";
|
||||
// "b_b4" was used after storing protx version for each masternode in evoDB
|
||||
static const std::string EVODB_BEST_BLOCK = "b_b4";
|
||||
|
||||
class CEvoDB;
|
||||
|
||||
|
@ -23,9 +23,12 @@ maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
||||
}
|
||||
|
||||
if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
||||
if (keyIDOwner.IsNull() || !pubKeyOperator.Get().IsValid() || keyIDVoting.IsNull()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
||||
}
|
||||
if (pubKeyOperator.IsLegacy() != (nVersion == LEGACY_BLS_VERSION)) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-operator-pubkey"};
|
||||
}
|
||||
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||
}
|
||||
@ -81,7 +84,7 @@ std::string CProRegTx::ToString() const
|
||||
}
|
||||
|
||||
return strprintf("CProRegTx(nVersion=%d, nType=%d, collateralOutpoint=%s, addr=%s, nOperatorReward=%f, ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, scriptPayout=%s, platformNodeID=%s, platformP2PPort=%d, platformHTTPPort=%d)",
|
||||
nVersion, ToUnderlying(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
|
||||
nVersion, ToUnderlying(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
|
||||
}
|
||||
|
||||
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
@ -114,9 +117,12 @@ maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
||||
}
|
||||
|
||||
if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
||||
if (!pubKeyOperator.Get().IsValid() || keyIDVoting.IsNull()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
||||
}
|
||||
if (pubKeyOperator.IsLegacy() != (nVersion == LEGACY_BLS_VERSION)) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-operator-pubkey"};
|
||||
}
|
||||
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-payee"};
|
||||
}
|
||||
@ -132,7 +138,7 @@ std::string CProUpRegTx::ToString() const
|
||||
}
|
||||
|
||||
return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, pubKeyOperator=%s, votingAddress=%s, payoutAddress=%s)",
|
||||
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), payee);
|
||||
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee);
|
||||
}
|
||||
|
||||
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
uint16_t platformP2PPort{0};
|
||||
uint16_t platformHTTPPort{0};
|
||||
CKeyID keyIDOwner;
|
||||
CBLSPublicKey pubKeyOperator;
|
||||
CBLSLazyPublicKey pubKeyOperator;
|
||||
CKeyID keyIDVoting;
|
||||
uint16_t nOperatorReward{0};
|
||||
CScript scriptPayout;
|
||||
@ -65,7 +65,7 @@ public:
|
||||
obj.collateralOutpoint,
|
||||
obj.addr,
|
||||
obj.keyIDOwner,
|
||||
CBLSPublicKeyVersionWrapper(const_cast<CBLSPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
obj.keyIDVoting,
|
||||
obj.nOperatorReward,
|
||||
obj.scriptPayout,
|
||||
@ -104,7 +104,7 @@ public:
|
||||
if (ExtractDestination(scriptPayout, dest)) {
|
||||
obj.pushKV("payoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION));
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
|
||||
obj.pushKV("operatorReward", (double)nOperatorReward / 100);
|
||||
if (nType == MnType::HighPerformance) {
|
||||
obj.pushKV("platformNodeID", platformNodeID.ToString());
|
||||
@ -212,7 +212,7 @@ public:
|
||||
uint16_t nVersion{LEGACY_BLS_VERSION}; // message version
|
||||
uint256 proTxHash;
|
||||
uint16_t nMode{0}; // only 0 supported for now
|
||||
CBLSPublicKey pubKeyOperator;
|
||||
CBLSLazyPublicKey pubKeyOperator;
|
||||
CKeyID keyIDVoting;
|
||||
CScript scriptPayout;
|
||||
uint256 inputsHash; // replay protection
|
||||
@ -230,7 +230,7 @@ public:
|
||||
READWRITE(
|
||||
obj.proTxHash,
|
||||
obj.nMode,
|
||||
CBLSPublicKeyVersionWrapper(const_cast<CBLSPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
obj.keyIDVoting,
|
||||
obj.scriptPayout,
|
||||
obj.inputsHash
|
||||
@ -255,7 +255,7 @@ public:
|
||||
if (ExtractDestination(scriptPayout, dest)) {
|
||||
obj.pushKV("payoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION));
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
|
||||
obj.pushKV("inputsHash", inputsHash.ToString());
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ CSimplifiedMNListEntry::CSimplifiedMNListEntry(const CDeterministicMN& dmn) :
|
||||
isValid(!dmn.pdmnState->IsBanned()),
|
||||
scriptPayout(dmn.pdmnState->scriptPayout),
|
||||
scriptOperatorPayout(dmn.pdmnState->scriptOperatorPayout),
|
||||
nVersion(dmn.pdmnState->nVersion == CProRegTx::LEGACY_BLS_VERSION ? LEGACY_BLS_VERSION : BASIC_BLS_VERSION),
|
||||
nType(dmn.nType),
|
||||
platformHTTPPort(dmn.pdmnState->platformHTTPPort),
|
||||
platformNodeID(dmn.pdmnState->platformNodeID)
|
||||
@ -57,18 +58,19 @@ std::string CSimplifiedMNListEntry::ToString() const
|
||||
operatorPayoutAddress = EncodeDestination(dest);
|
||||
}
|
||||
|
||||
return strprintf("CSimplifiedMNListEntry(nType=%d, proRegTxHash=%s, confirmedHash=%s, service=%s, pubKeyOperator=%s, votingAddress=%s, isValid=%d, payoutAddress=%s, operatorPayoutAddress=%s, platformHTTPPort=%d, platformNodeID=%s)",
|
||||
ToUnderlying(nType), proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), EncodeDestination(PKHash(keyIDVoting)), isValid, payoutAddress, operatorPayoutAddress, platformHTTPPort, platformNodeID.ToString());
|
||||
return strprintf("CSimplifiedMNListEntry(nVersion=%d, nType=%d, proRegTxHash=%s, confirmedHash=%s, service=%s, pubKeyOperator=%s, votingAddress=%s, isValid=%d, payoutAddress=%s, operatorPayoutAddress=%s, platformHTTPPort=%d, platformNodeID=%s)",
|
||||
nVersion, ToUnderlying(nType), proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), isValid, payoutAddress, operatorPayoutAddress, platformHTTPPort, platformNodeID.ToString());
|
||||
}
|
||||
|
||||
void CSimplifiedMNListEntry::ToJson(UniValue& obj, bool extended) const
|
||||
{
|
||||
obj.clear();
|
||||
obj.setObject();
|
||||
obj.pushKV("nVersion", nVersion);
|
||||
obj.pushKV("proRegTxHash", proRegTxHash.ToString());
|
||||
obj.pushKV("confirmedHash", confirmedHash.ToString());
|
||||
obj.pushKV("service", service.ToString(false));
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.Get().ToString());
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
|
||||
obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
|
||||
obj.pushKV("isValid", isValid);
|
||||
obj.pushKV("nVersion", nVersion);
|
||||
@ -102,15 +104,13 @@ CSimplifiedMNList::CSimplifiedMNList(const std::vector<CSimplifiedMNListEntry>&
|
||||
});
|
||||
}
|
||||
|
||||
CSimplifiedMNList::CSimplifiedMNList(const CDeterministicMNList& dmnList, bool isV19Active)
|
||||
CSimplifiedMNList::CSimplifiedMNList(const CDeterministicMNList& dmnList)
|
||||
{
|
||||
mnList.resize(dmnList.GetAllMNsCount());
|
||||
|
||||
size_t i = 0;
|
||||
dmnList.ForEachMN(false, [this, &i, isV19Active](auto& dmn) {
|
||||
auto sme = std::make_unique<CSimplifiedMNListEntry>(dmn);
|
||||
sme->nVersion = isV19Active ? CSimplifiedMNListEntry::BASIC_BLS_VERSION : CSimplifiedMNListEntry::LEGACY_BLS_VERSION;
|
||||
mnList[i++] = std::move(sme);
|
||||
dmnList.ForEachMN(false, [this, &i](auto& dmn) {
|
||||
mnList[i++] = std::make_unique<CSimplifiedMNListEntry>(dmn);
|
||||
});
|
||||
|
||||
std::sort(mnList.begin(), mnList.end(), [&](const std::unique_ptr<CSimplifiedMNListEntry>& a, const std::unique_ptr<CSimplifiedMNListEntry>& b) {
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
uint160 platformNodeID{};
|
||||
CScript scriptPayout; // mem-only
|
||||
CScript scriptOperatorPayout; // mem-only
|
||||
uint16_t nVersion{LEGACY_BLS_VERSION}; // mem-only
|
||||
uint16_t nVersion{LEGACY_BLS_VERSION};
|
||||
|
||||
CSimplifiedMNListEntry() = default;
|
||||
explicit CSimplifiedMNListEntry(const CDeterministicMN& dmn);
|
||||
@ -65,6 +65,9 @@ public:
|
||||
|
||||
SERIALIZE_METHODS(CSimplifiedMNListEntry, obj)
|
||||
{
|
||||
if ((s.GetType() & SER_NETWORK) && s.GetVersion() >= SMNLE_VERSIONED_PROTO_VERSION) {
|
||||
READWRITE(obj.nVersion);
|
||||
}
|
||||
READWRITE(
|
||||
obj.proRegTxHash,
|
||||
obj.confirmedHash,
|
||||
@ -98,7 +101,7 @@ public:
|
||||
|
||||
CSimplifiedMNList() = default;
|
||||
explicit CSimplifiedMNList(const std::vector<CSimplifiedMNListEntry>& smlEntries);
|
||||
explicit CSimplifiedMNList(const CDeterministicMNList& dmnList, bool isV19Active);
|
||||
explicit CSimplifiedMNList(const CDeterministicMNList& dmnList);
|
||||
|
||||
uint256 CalcMerkleRoot(bool* pmutated = nullptr) const;
|
||||
bool operator==(const CSimplifiedMNList& rhs) const;
|
||||
@ -121,8 +124,7 @@ public:
|
||||
class CSimplifiedMNListDiff
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t LEGACY_BLS_VERSION = 1;
|
||||
static constexpr uint16_t BASIC_BLS_VERSION = 2;
|
||||
static constexpr uint16_t CURRENT_VERSION = 1;
|
||||
|
||||
uint256 baseBlockHash;
|
||||
uint256 blockHash;
|
||||
@ -130,7 +132,7 @@ public:
|
||||
CTransactionRef cbTx;
|
||||
std::vector<uint256> deletedMNs;
|
||||
std::vector<CSimplifiedMNListEntry> mnList;
|
||||
uint16_t nVersion{LEGACY_BLS_VERSION};
|
||||
uint16_t nVersion{CURRENT_VERSION};
|
||||
|
||||
std::vector<std::pair<uint8_t, uint256>> deletedQuorums; // p<LLMQType, quorumHash>
|
||||
std::vector<llmq::CFinalCommitment> newQuorums;
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
uint256 CalcTxInputsHash(const CTransaction& tx)
|
||||
{
|
||||
CHashWriter hw(CLIENT_VERSION, SER_GETHASH);
|
||||
CHashWriter hw(SER_GETHASH, CLIENT_VERSION);
|
||||
for (const auto& in : tx.vin) {
|
||||
hw << in.prevout;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <hash.h>
|
||||
#include <llmq/blockprocessor.h>
|
||||
#include <llmq/commitment.h>
|
||||
#include <llmq/utils.h>
|
||||
#include <primitives/block.h>
|
||||
#include <validation.h>
|
||||
|
||||
@ -152,6 +153,13 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
|
||||
int64_t nTime5 = GetTimeMicros();
|
||||
nTimeMerkle += nTime5 - nTime4;
|
||||
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
|
||||
|
||||
if (llmq::utils::V19ActivationHeight(pindex) == pindex->nHeight + 1) {
|
||||
// NOTE: The block next to the activation is the one that is using new rules.
|
||||
// V19 activated just activated, so we must switch to the new rules here.
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock");
|
||||
@ -164,7 +172,16 @@ bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq:
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
auto bls_legacy_scheme = bls::bls_legacy_scheme.load();
|
||||
|
||||
try {
|
||||
if (llmq::utils::V19ActivationHeight(pindex) == pindex->nHeight + 1) {
|
||||
// NOTE: The block next to the activation is the one that is using new rules.
|
||||
// Removing the activation block here, so we must switch back to the old rules.
|
||||
bls::bls_legacy_scheme.store(true);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
for (int i = (int)block.vtx.size() - 1; i >= 0; --i) {
|
||||
const CTransaction& tx = *block.vtx[i];
|
||||
if (!UndoSpecialTx(tx, pindex)) {
|
||||
@ -180,6 +197,8 @@ bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq:
|
||||
return false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
bls::bls_legacy_scheme.store(bls_legacy_scheme);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
return error(strprintf("%s -- failed: %s\n", __func__, e.what()).c_str());
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,7 @@ bool CGovernanceObject::CheckSignature(const CBLSPublicKey& pubKey) const
|
||||
{
|
||||
CBLSSignature sig;
|
||||
const auto pindex = llmq::utils::V19ActivationIndex(::ChainActive().Tip());
|
||||
bool is_bls_legacy_scheme = pindex == nullptr || nTime < pindex->nTime;
|
||||
bool is_bls_legacy_scheme = pindex == nullptr || nTime < pindex->pprev->nTime;
|
||||
sig.SetByteVector(vchSig, is_bls_legacy_scheme);
|
||||
if (!sig.VerifyInsecure(pubKey, GetSignatureHash(), is_bls_legacy_scheme)) {
|
||||
LogPrintf("CGovernanceObject::CheckSignature -- VerifyInsecure() failed\n");
|
||||
@ -501,7 +501,7 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingConf
|
||||
|
||||
// Check that we have a valid MN signature
|
||||
if (!CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
|
||||
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.Get().ToString();
|
||||
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.ToString();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ bool CGovernanceVote::CheckSignature(const CBLSPublicKey& pubKey) const
|
||||
{
|
||||
CBLSSignature sig;
|
||||
const auto pindex = llmq::utils::V19ActivationIndex(::ChainActive().Tip());
|
||||
bool is_bls_legacy_scheme = pindex == nullptr || nTime < pindex->nTime;
|
||||
bool is_bls_legacy_scheme = pindex == nullptr || nTime < pindex->pprev->nTime;
|
||||
sig.SetByteVector(vchSig, is_bls_legacy_scheme);
|
||||
if (!sig.VerifyInsecure(pubKey, GetSignatureHash(), is_bls_legacy_scheme)) {
|
||||
LogPrintf("CGovernanceVote::CheckSignature -- VerifyInsecure() failed\n");
|
||||
|
28
src/init.cpp
28
src/init.cpp
@ -734,14 +734,14 @@ void SetupServerArgs(NodeContext& node)
|
||||
argsman.AddArg("-pushversion", "Protocol version to report to other nodes", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-sporkaddr=<dashaddress>", "Override spork address. Only useful for regtest and devnet. Using this on mainnet or testnet will ban you.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-sporkkey=<privatekey>", "Set the private key to be used for signing spork messages.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-sporkkey=<privatekey>", "Set the private key to be used for signing spork messages.", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||
|
||||
SetupChainParamsBaseOptions(argsman);
|
||||
|
||||
argsman.AddArg("-llmq-data-recovery=<n>", strprintf("Enable automated quorum data recovery (default: %u)", llmq::DEFAULT_ENABLE_QUORUM_DATA_RECOVERY), ArgsManager::ALLOW_ANY, OptionsCategory::MASTERNODE);
|
||||
argsman.AddArg("-llmq-qvvec-sync=<quorum_name>:<mode>", strprintf("Defines from which LLMQ type the masternode should sync quorum verification vectors. Can be used multiple times with different LLMQ types. <mode>: %d (sync always from all quorums of the type defined by <quorum_name>), %d (sync from all quorums of the type defined by <quorum_name> if a member of any of the quorums)", (int32_t)llmq::QvvecSyncMode::Always, (int32_t)llmq::QvvecSyncMode::OnlyIfTypeMember), ArgsManager::ALLOW_ANY, OptionsCategory::MASTERNODE);
|
||||
argsman.AddArg("-masternodeblsprivkey=<hex>", "Set the masternode BLS private key and enable the client to act as a masternode", ArgsManager::ALLOW_ANY, OptionsCategory::MASTERNODE);
|
||||
argsman.AddArg("-masternodeblsprivkey=<hex>", "Set the masternode BLS private key and enable the client to act as a masternode", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::MASTERNODE);
|
||||
argsman.AddArg("-platform-user=<user>", "Set the username for the \"platform user\", a restricted user intended to be used by Dash Platform, to the specified username.", ArgsManager::ALLOW_ANY, OptionsCategory::MASTERNODE);
|
||||
|
||||
argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
|
||||
@ -1702,7 +1702,10 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>(keyOperator);
|
||||
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>(keyOperator.GetPublicKey());
|
||||
}
|
||||
LogPrintf("MASTERNODE:\n blsPubKeyOperator: %s\n", activeMasternodeInfo.blsPubKeyOperator->ToString());
|
||||
// We don't know the actual scheme at this point, print both
|
||||
LogPrintf("MASTERNODE:\n blsPubKeyOperator legacy: %s\n blsPubKeyOperator basic: %s\n",
|
||||
activeMasternodeInfo.blsPubKeyOperator->ToString(true),
|
||||
activeMasternodeInfo.blsPubKeyOperator->ToString(false));
|
||||
} else {
|
||||
LOCK(activeMasternodeInfoCs);
|
||||
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>();
|
||||
@ -2016,6 +2019,8 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
LOCK(cs_main);
|
||||
node.evodb.reset();
|
||||
node.evodb = std::make_unique<CEvoDB>(nEvoDbCache, false, fReset || fReindexChainState);
|
||||
|
||||
chainman.Reset();
|
||||
chainman.InitializeChainstate(llmq::chainLocksHandler, llmq::quorumInstantSendManager, llmq::quorumBlockProcessor, node.evodb, *Assert(node.mempool));
|
||||
chainman.m_total_coinstip_cache = nCoinCacheUsage;
|
||||
chainman.m_total_coinsdb_cache = nCoinDBCache;
|
||||
@ -2168,6 +2173,10 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
strLoadError = _("Error upgrading evo database");
|
||||
break;
|
||||
}
|
||||
if (!deterministicMNManager->MigrateDBIfNeeded2()) {
|
||||
strLoadError = _("Error upgrading evo database");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!llmq::quorumBlockProcessor->UpgradeDB()) {
|
||||
strLoadError = _("Error upgrading evo database");
|
||||
@ -2192,8 +2201,11 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
break;
|
||||
}
|
||||
|
||||
if (llmq::utils::IsV19Active(tip))
|
||||
bool v19active = llmq::utils::IsV19Active(tip);
|
||||
if (llmq::utils::IsV19Active(tip)) {
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
// Only verify the DB of the active chainstate. This is fixed in later
|
||||
// work when we allow VerifyDB to be parameterized by chainstate.
|
||||
@ -2207,6 +2219,14 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
failed_verification = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// VerifyDB() disconnects blocks which might result in us switching back to legacy.
|
||||
// Make sure we use the right scheme.
|
||||
if (v19active && bls::bls_legacy_scheme.load()) {
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
} else {
|
||||
// TODO: CEvoDB instance should probably be a part of CChainState
|
||||
// (for multiple chainstates to actually work in parallel)
|
||||
|
@ -146,9 +146,6 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
|
||||
return true;
|
||||
}
|
||||
|
||||
if (utils::IsV19Active(pindex->pprev))
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
|
||||
llmq::utils::PreComputeQuorumMembers(pindex);
|
||||
|
||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||
@ -307,9 +304,6 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
if (!utils::IsV19Active(pindex->pprev))
|
||||
bls::bls_legacy_scheme.store(true);
|
||||
|
||||
llmq::utils::PreComputeQuorumMembers(pindex, true);
|
||||
|
||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||
|
@ -247,6 +247,10 @@ void CChainLocksHandler::TrySignChainTip()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ChainLocksSigningEnabled(spork_manager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const CBlockIndex* pindex = WITH_LOCK(cs_main, return ::ChainActive().Tip());
|
||||
|
||||
if (pindex->pprev == nullptr) {
|
||||
@ -678,4 +682,9 @@ bool AreChainLocksEnabled(const CSporkManager& sporkManager)
|
||||
return sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED);
|
||||
}
|
||||
|
||||
bool ChainLocksSigningEnabled(const CSporkManager& sporkManager)
|
||||
{
|
||||
return sporkManager.GetSporkValue(SPORK_19_CHAINLOCKS_ENABLED) == 0;
|
||||
}
|
||||
|
||||
} // namespace llmq
|
||||
|
@ -119,6 +119,7 @@ private:
|
||||
extern std::unique_ptr<CChainLocksHandler> chainLocksHandler;
|
||||
|
||||
bool AreChainLocksEnabled(const CSporkManager& sporkManager);
|
||||
bool ChainLocksSigningEnabled(const CSporkManager& sporkManager);
|
||||
|
||||
} // namespace llmq
|
||||
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
CRecoveredSig(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash, const CBLSLazySignature& _sig) :
|
||||
CSigBase(_llmqType, _quorumHash, _id, _msgHash), sig(_sig) {UpdateHash();};
|
||||
CRecoveredSig(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash, const CBLSSignature& _sig) :
|
||||
CSigBase(_llmqType, _quorumHash, _id, _msgHash) {const_cast<CBLSLazySignature&>(sig).Set(_sig); UpdateHash();};
|
||||
CSigBase(_llmqType, _quorumHash, _id, _msgHash) {const_cast<CBLSLazySignature&>(sig).Set(_sig, bls::bls_legacy_scheme.load()); UpdateHash();};
|
||||
|
||||
private:
|
||||
// only in-memory
|
||||
|
@ -1514,7 +1514,7 @@ std::optional<CSigShare> CSigSharesManager::CreateSigShare(const CQuorumCPtr& qu
|
||||
CSigShare sigShare(quorum->params.type, quorum->qc->quorumHash, id, msgHash, uint16_t(memberIdx), {});
|
||||
uint256 signHash = sigShare.buildSignHash();
|
||||
|
||||
sigShare.sigShare.Set(skShare.Sign(signHash));
|
||||
sigShare.sigShare.Set(skShare.Sign(signHash), bls::bls_legacy_scheme.load());
|
||||
if (!sigShare.sigShare.Get().IsValid()) {
|
||||
LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__,
|
||||
signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), t.count());
|
||||
|
@ -573,7 +573,7 @@ uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHa
|
||||
const std::vector<bool>& validMembers, const CBLSPublicKey& pubKey,
|
||||
const uint256& vvecHash)
|
||||
{
|
||||
CHashWriter hw(SER_NETWORK, 0);
|
||||
CHashWriter hw(SER_GETHASH, 0);
|
||||
hw << llmqType;
|
||||
hw << blockHash;
|
||||
hw << DYNBITSET(validMembers);
|
||||
@ -659,16 +659,21 @@ bool IsV19Active(const CBlockIndex* pindex)
|
||||
return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19, llmq_versionbitscache) == ThresholdState::ACTIVE;
|
||||
}
|
||||
|
||||
const CBlockIndex* V19ActivationIndex(const CBlockIndex* pindex)
|
||||
const int V19ActivationHeight(const CBlockIndex* pindex)
|
||||
{
|
||||
assert(pindex);
|
||||
|
||||
LOCK(cs_llmq_vbc);
|
||||
if (VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19, llmq_versionbitscache) != ThresholdState::ACTIVE) {
|
||||
return nullptr;
|
||||
}
|
||||
int nHeight = VersionBitsStateSinceHeight(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19, llmq_versionbitscache);
|
||||
return pindex->GetAncestor(nHeight);
|
||||
LOCK(cs_llmq_vbc);
|
||||
if (VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19, llmq_versionbitscache) != ThresholdState::ACTIVE) {
|
||||
return -1;
|
||||
}
|
||||
return VersionBitsStateSinceHeight(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19, llmq_versionbitscache);
|
||||
}
|
||||
|
||||
const CBlockIndex* V19ActivationIndex(const CBlockIndex* pindex)
|
||||
{
|
||||
assert(pindex);
|
||||
return pindex->GetAncestor(V19ActivationHeight(pindex));
|
||||
}
|
||||
|
||||
bool IsInstantSendLLMQTypeShared()
|
||||
|
@ -84,6 +84,7 @@ Consensus::LLMQType GetInstantSendLLMQType(const CQuorumManager& qman, const CBl
|
||||
Consensus::LLMQType GetInstantSendLLMQType(bool deterministic);
|
||||
bool IsDIP0024Active(const CBlockIndex* pindex);
|
||||
bool IsV19Active(const CBlockIndex* pindex);
|
||||
const int V19ActivationHeight(const CBlockIndex* pindex);
|
||||
const CBlockIndex* V19ActivationIndex(const CBlockIndex* pindex);
|
||||
|
||||
/// Returns the state of `-llmq-data-recovery`
|
||||
|
@ -131,6 +131,7 @@ void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
|
||||
|
||||
activeMasternodeInfo.proTxHash = dmn->proTxHash;
|
||||
activeMasternodeInfo.outpoint = dmn->collateralOutpoint;
|
||||
activeMasternodeInfo.legacy = dmn->pdmnState->nVersion == CProRegTx::LEGACY_BLS_VERSION;
|
||||
state = MASTERNODE_READY;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ struct CActiveMasternodeInfo {
|
||||
uint256 proTxHash;
|
||||
COutPoint outpoint;
|
||||
CService service;
|
||||
bool legacy{true};
|
||||
};
|
||||
|
||||
|
||||
|
@ -181,6 +181,10 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
|
||||
// Note: GetNextWorkRequiredBTC has it's own special difficulty rule,
|
||||
// so we only apply this to post-BTC algos.
|
||||
if (params.fPowNoRetargeting) {
|
||||
return bnPowLimit.GetCompact();
|
||||
}
|
||||
|
||||
if (params.fPowAllowMinDifficultyBlocks) {
|
||||
// recent block is more than 2 hours old
|
||||
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + 2 * 60 * 60) {
|
||||
|
@ -460,7 +460,7 @@ void BitcoinGUI::createActions()
|
||||
|
||||
// Jump directly to tabs in RPC-console
|
||||
connect(openInfoAction, &QAction::triggered, this, &BitcoinGUI::showInfo);
|
||||
connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow);
|
||||
connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showConsole);
|
||||
connect(openGraphAction, &QAction::triggered, this, &BitcoinGUI::showGraph);
|
||||
connect(openPeersAction, &QAction::triggered, this, &BitcoinGUI::showPeers);
|
||||
connect(openRepairAction, &QAction::triggered, this, &BitcoinGUI::showRepair);
|
||||
|
@ -38,7 +38,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
|
||||
ui(new Ui::OptionsDialog),
|
||||
model(nullptr),
|
||||
mapper(nullptr),
|
||||
pageButtons(nullptr)
|
||||
pageButtons(nullptr),
|
||||
m_enable_wallet(enableWallet)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@ -108,7 +109,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
|
||||
pageButtons = new QButtonGroup(this);
|
||||
pageButtons->addButton(ui->btnMain, pageButtons->buttons().size());
|
||||
/* Remove Wallet/CoinJoin tabs and 3rd party-URL textbox in case of -disablewallet */
|
||||
if (!enableWallet) {
|
||||
if (!m_enable_wallet) {
|
||||
ui->stackedWidgetOptions->removeWidget(ui->pageWallet);
|
||||
ui->btnWallet->hide();
|
||||
ui->stackedWidgetOptions->removeWidget(ui->pageCoinJoin);
|
||||
@ -396,9 +397,11 @@ void OptionsDialog::on_okButton_clicked()
|
||||
mapper->submit();
|
||||
appearance->accept();
|
||||
#ifdef ENABLE_WALLET
|
||||
for (auto& wallet : model->node().walletClient().getWallets()) {
|
||||
wallet->coinJoin().resetCachedBlocks();
|
||||
wallet->markDirty();
|
||||
if (m_enable_wallet) {
|
||||
for (auto& wallet : model->node().walletClient().getWallets()) {
|
||||
wallet->coinJoin().resetCachedBlocks();
|
||||
wallet->markDirty();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WALLET
|
||||
accept();
|
||||
|
@ -89,6 +89,7 @@ private:
|
||||
QString previousTheme;
|
||||
AppearanceWidget* appearance;
|
||||
bool fCoinJoinEnabledPrev{false};
|
||||
bool m_enable_wallet{false};
|
||||
|
||||
void showEvent(QShowEvent* event) override;
|
||||
};
|
||||
|
@ -86,6 +86,7 @@ SendCoinsDialog::SendCoinsDialog(bool _fCoinJoin, QWidget* parent) :
|
||||
GUIUtil::setFont({ui->labelCoinControlFeatures
|
||||
}, GUIUtil::FontWeight::Bold, 16);
|
||||
|
||||
ui->checkBoxCoinControlChange->setEnabled(!_fCoinJoin);
|
||||
GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
|
||||
|
||||
addEntry();
|
||||
|
@ -184,9 +184,7 @@ static CKeyID ParsePubKeyIDFromAddress(const std::string& strAddress, const std:
|
||||
static CBLSPublicKey ParseBLSPubKey(const std::string& hexKey, const std::string& paramName, bool specific_legacy_bls_scheme = false)
|
||||
{
|
||||
CBLSPublicKey pubKey;
|
||||
bool is_bls_legacy_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
bool use_bls_scheme = specific_legacy_bls_scheme || is_bls_legacy_scheme;
|
||||
if (!pubKey.SetHexStr(hexKey, use_bls_scheme)) {
|
||||
if (!pubKey.SetHexStr(hexKey, specific_legacy_bls_scheme)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid BLS public key, not %s", paramName, hexKey));
|
||||
}
|
||||
return pubKey;
|
||||
@ -609,7 +607,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
}
|
||||
|
||||
bool isV19active = llmq::utils::IsV19Active(WITH_LOCK(cs_main, return ::ChainActive().Tip();));
|
||||
if (mnType == MnType::HighPerformance && !isV19active) {
|
||||
if (isHPMNrequested && !isV19active) {
|
||||
throw JSONRPCError(RPC_INVALID_REQUEST, "HPMN aren't allowed yet");
|
||||
}
|
||||
|
||||
@ -619,12 +617,9 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_REGISTER;
|
||||
|
||||
const bool use_legacy = isV19active ? specific_legacy_bls_scheme : true;
|
||||
|
||||
CProRegTx ptx;
|
||||
if (specific_legacy_bls_scheme && !isHPMNrequested) {
|
||||
ptx.nVersion = CProRegTx::LEGACY_BLS_VERSION;
|
||||
} else {
|
||||
ptx.nVersion = CProRegTx::GetVersion(isV19active);
|
||||
}
|
||||
ptx.nType = mnType;
|
||||
|
||||
if (isFundRegister) {
|
||||
@ -661,7 +656,10 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
}
|
||||
|
||||
ptx.keyIDOwner = ParsePubKeyIDFromAddress(request.params[paramIdx + 1].get_str(), "owner address");
|
||||
CBLSPublicKey pubKeyOperator = ParseBLSPubKey(request.params[paramIdx + 2].get_str(), "operator BLS address", specific_legacy_bls_scheme && !isHPMNrequested);
|
||||
ptx.pubKeyOperator.Set(ParseBLSPubKey(request.params[paramIdx + 2].get_str(), "operator BLS address", use_legacy), use_legacy);
|
||||
ptx.nVersion = use_legacy ? CProRegTx::LEGACY_BLS_VERSION : CProRegTx::BASIC_BLS_VERSION;
|
||||
CHECK_NONFATAL(ptx.pubKeyOperator.IsLegacy() == (ptx.nVersion == CProRegTx::LEGACY_BLS_VERSION));
|
||||
|
||||
CKeyID keyIDVoting = ptx.keyIDOwner;
|
||||
|
||||
if (request.params[paramIdx + 3].get_str() != "") {
|
||||
@ -703,7 +701,6 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
paramIdx += 3;
|
||||
}
|
||||
|
||||
ptx.pubKeyOperator = pubKeyOperator;
|
||||
ptx.keyIDVoting = keyIDVoting;
|
||||
ptx.scriptPayout = GetScriptForDestination(payoutDest);
|
||||
|
||||
@ -905,7 +902,6 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques
|
||||
}
|
||||
|
||||
CProUpServTx ptx;
|
||||
ptx.nVersion = CProUpServTx::GetVersion(llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
ptx.nType = mnType;
|
||||
ptx.proTxHash = ParseHashV(request.params[0], "proTxHash");
|
||||
|
||||
@ -944,6 +940,7 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques
|
||||
if (dmn->nType != mnType) {
|
||||
throw std::runtime_error(strprintf("masternode with proTxHash %s is not a %s", ptx.proTxHash.ToString(), GetMnType(mnType).description));
|
||||
}
|
||||
ptx.nVersion = dmn->pdmnState->nVersion;
|
||||
|
||||
if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator.Get()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key"));
|
||||
@ -1030,24 +1027,28 @@ static UniValue protx_update_registrar_wrapper(const JSONRPCRequest& request, co
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
|
||||
CProUpRegTx ptx;
|
||||
if (specific_legacy_bls_scheme) {
|
||||
ptx.nVersion = CProUpRegTx::LEGACY_BLS_VERSION;
|
||||
} else {
|
||||
ptx.nVersion = CProUpRegTx::GetVersion(llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
}
|
||||
ptx.proTxHash = ParseHashV(request.params[0], "proTxHash");
|
||||
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(ptx.proTxHash);
|
||||
if (!dmn) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString()));
|
||||
}
|
||||
ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator.Get();
|
||||
ptx.keyIDVoting = dmn->pdmnState->keyIDVoting;
|
||||
ptx.scriptPayout = dmn->pdmnState->scriptPayout;
|
||||
|
||||
const bool use_legacy = llmq::utils::IsV19Active(::ChainActive().Tip()) ? specific_legacy_bls_scheme : true;
|
||||
|
||||
if (request.params[1].get_str() != "") {
|
||||
ptx.pubKeyOperator = ParseBLSPubKey(request.params[1].get_str(), "operator BLS address", specific_legacy_bls_scheme);
|
||||
// new pubkey
|
||||
ptx.pubKeyOperator.Set(ParseBLSPubKey(request.params[1].get_str(), "operator BLS address", use_legacy), use_legacy);
|
||||
} else {
|
||||
// same pubkey, reuse as is
|
||||
ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator;
|
||||
}
|
||||
|
||||
ptx.nVersion = use_legacy ? CProUpRegTx::LEGACY_BLS_VERSION : CProUpRegTx::BASIC_BLS_VERSION;
|
||||
CHECK_NONFATAL(ptx.pubKeyOperator.IsLegacy() == (ptx.nVersion == CProUpRegTx::LEGACY_BLS_VERSION));
|
||||
|
||||
if (request.params[2].get_str() != "") {
|
||||
ptx.keyIDVoting = ParsePubKeyIDFromAddress(request.params[2].get_str(), "voting address");
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
|
||||
bool fMnFound = WITH_LOCK(activeMasternodeInfoCs, return mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint));
|
||||
|
||||
LogPrint(BCLog::GOBJECT, "gobject_submit -- pubKeyOperator = %s, outpoint = %s, params.size() = %lld, fMnFound = %d\n",
|
||||
(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A")),
|
||||
(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString(activeMasternodeInfo.legacy) : "N/A")),
|
||||
WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint.ToStringShort()), request.params.size(), fMnFound);
|
||||
|
||||
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
|
||||
|
@ -675,7 +675,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
|
||||
EncodeDestination(PKHash(dmn.pdmnState->keyIDOwner)) << " " <<
|
||||
EncodeDestination(PKHash(dmn.pdmnState->keyIDVoting)) << " " <<
|
||||
collateralAddressStr << " " <<
|
||||
dmn.pdmnState->pubKeyOperator.Get().ToString();
|
||||
dmn.pdmnState->pubKeyOperator.ToString();
|
||||
std::string strInfo = streamInfo.str();
|
||||
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
|
||||
strOutpoint.find(strFilter) == std::string::npos) return;
|
||||
@ -697,7 +697,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
|
||||
objMN.pushKV("owneraddress", EncodeDestination(PKHash(dmn.pdmnState->keyIDOwner)));
|
||||
objMN.pushKV("votingaddress", EncodeDestination(PKHash(dmn.pdmnState->keyIDVoting)));
|
||||
objMN.pushKV("collateraladdress", collateralAddressStr);
|
||||
objMN.pushKV("pubkeyoperator", dmn.pdmnState->pubKeyOperator.Get().ToString());
|
||||
objMN.pushKV("pubkeyoperator", dmn.pdmnState->pubKeyOperator.ToString());
|
||||
obj.pushKV(strOutpoint, objMN);
|
||||
} else if (strMode == "lastpaidblock") {
|
||||
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
|
||||
@ -714,7 +714,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
|
||||
obj.pushKV(strOutpoint, EncodeDestination(PKHash(dmn.pdmnState->keyIDOwner)));
|
||||
} else if (strMode == "pubkeyoperator") {
|
||||
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
|
||||
obj.pushKV(strOutpoint, dmn.pdmnState->pubKeyOperator.Get().ToString());
|
||||
obj.pushKV(strOutpoint, dmn.pdmnState->pubKeyOperator.ToString());
|
||||
} else if (strMode == "status") {
|
||||
std::string strStatus = dmnToStatus(dmn);
|
||||
if (strFilter !="" && strStatus.find(strFilter) == std::string::npos &&
|
||||
|
@ -210,7 +210,7 @@ static UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMem
|
||||
UniValue mo(UniValue::VOBJ);
|
||||
mo.pushKV("proTxHash", dmn->proTxHash.ToString());
|
||||
mo.pushKV("service", dmn->pdmnState->addr.ToString());
|
||||
mo.pushKV("pubKeyOperator", dmn->pdmnState->pubKeyOperator.Get().ToString());
|
||||
mo.pushKV("pubKeyOperator", dmn->pdmnState->pubKeyOperator.ToString());
|
||||
mo.pushKV("valid", quorum->qc->validMembers[i]);
|
||||
if (quorum->qc->validMembers[i]) {
|
||||
CBLSPublicKey pubKey = quorum->GetPubKeyShare(i);
|
||||
|
@ -125,7 +125,7 @@ static CMutableTransaction CreateProRegTx(const CTxMemPool& mempool, SimpleUTXOM
|
||||
proTx.collateralOutpoint.n = 0;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.keyIDOwner = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.pubKeyOperator = operatorKeyRet.GetPublicKey();
|
||||
proTx.pubKeyOperator.Set(operatorKeyRet.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
proTx.keyIDVoting = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <evo/specialtx.h>
|
||||
#include <evo/providertx.h>
|
||||
#include <evo/deterministicmns.h>
|
||||
#include <llmq/utils.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@ -103,7 +104,7 @@ static CMutableTransaction CreateProRegTx(const CTxMemPool& mempool, SimpleUTXOM
|
||||
proTx.collateralOutpoint.n = 0;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.keyIDOwner = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.pubKeyOperator = operatorKeyRet.GetPublicKey();
|
||||
proTx.pubKeyOperator.Set(operatorKeyRet.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
proTx.keyIDVoting = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
@ -143,7 +144,7 @@ static CMutableTransaction CreateProUpRegTx(const CTxMemPool& mempool, SimpleUTX
|
||||
CProUpRegTx proTx;
|
||||
proTx.nVersion = CProUpRegTx::GetVersion(!bls::bls_legacy_scheme);
|
||||
proTx.proTxHash = proTxHash;
|
||||
proTx.pubKeyOperator = pubKeyOperator;
|
||||
proTx.pubKeyOperator.Set(pubKeyOperator, bls::bls_legacy_scheme.load());
|
||||
proTx.keyIDVoting = keyIDVoting;
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
@ -264,6 +265,136 @@ void FuncDIP3Activation(TestChainSetup& setup)
|
||||
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
|
||||
};
|
||||
|
||||
void FuncV19Activation(TestChainSetup& setup)
|
||||
{
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
|
||||
// create
|
||||
auto utxos = BuildSimpleUtxoMap(setup.m_coinbase_txns);
|
||||
CKey owner_key;
|
||||
CBLSSecretKey operator_key;
|
||||
CKey collateral_key;
|
||||
collateral_key.MakeNewKey(false);
|
||||
auto collateralScript = GetScriptForDestination(PKHash(collateral_key.GetPubKey()));
|
||||
auto tx_reg = CreateProRegTx(*(setup.m_node.mempool), utxos, 1, collateralScript, setup.coinbaseKey, owner_key, operator_key);
|
||||
auto tx_reg_hash = tx_reg.GetHash();
|
||||
|
||||
int nHeight = ::ChainActive().Height();
|
||||
|
||||
auto block = std::make_shared<CBlock>(setup.CreateBlock({tx_reg}, setup.coinbaseKey));
|
||||
BOOST_ASSERT(Assert(setup.m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
auto tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(tip_list.HasMN(tx_reg_hash));
|
||||
auto pindex_create = ::ChainActive().Tip();
|
||||
auto base_list = deterministicMNManager->GetListForBlock(pindex_create);
|
||||
std::vector<CDeterministicMNListDiff> diffs;
|
||||
|
||||
// update
|
||||
CBLSSecretKey operator_key_new;
|
||||
operator_key_new.MakeNewKey();
|
||||
auto tx_upreg = CreateProUpRegTx(*(setup.m_node.mempool), utxos, tx_reg_hash, owner_key, operator_key_new.GetPublicKey(), owner_key.GetPubKey().GetID(), collateralScript, setup.coinbaseKey);
|
||||
|
||||
block = std::make_shared<CBlock>(setup.CreateBlock({tx_upreg}, setup.coinbaseKey));
|
||||
BOOST_ASSERT(Assert(setup.m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(tip_list.HasMN(tx_reg_hash));
|
||||
diffs.push_back(base_list.BuildDiff(tip_list));
|
||||
|
||||
// spend
|
||||
CMutableTransaction tx_spend;
|
||||
COutPoint collateralOutpoint(tx_reg_hash, 0);
|
||||
tx_spend.vin.emplace_back(collateralOutpoint);
|
||||
tx_spend.vout.emplace_back(999.99 * COIN, collateralScript);
|
||||
|
||||
FillableSigningProvider signing_provider;
|
||||
signing_provider.AddKeyPubKey(collateral_key, collateral_key.GetPubKey());
|
||||
BOOST_ASSERT(SignSignature(signing_provider, CTransaction(tx_reg), tx_spend, 0, SIGHASH_ALL));
|
||||
block = std::make_shared<CBlock>(setup.CreateBlock({tx_spend}, setup.coinbaseKey));
|
||||
BOOST_ASSERT(Assert(setup.m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
|
||||
// mine another block so that it's not the last one before V19
|
||||
setup.CreateAndProcessBlock({}, setup.coinbaseKey);
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
|
||||
// this block should activate V19
|
||||
setup.CreateAndProcessBlock({}, setup.coinbaseKey);
|
||||
BOOST_ASSERT(llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
|
||||
// check mn list/diff
|
||||
CDeterministicMNListDiff dummy_diff = base_list.BuildDiff(tip_list);
|
||||
CDeterministicMNList dummmy_list = base_list.ApplyDiff(::ChainActive().Tip(), dummy_diff);
|
||||
// Lists should match
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
|
||||
// mine 10 more blocks
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
setup.CreateAndProcessBlock({}, setup.coinbaseKey);
|
||||
BOOST_ASSERT(llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight + 1 + i);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
}
|
||||
|
||||
// check mn list/diff
|
||||
const CBlockIndex* v19_index = llmq::utils::V19ActivationIndex(::ChainActive().Tip());
|
||||
auto v19_list = deterministicMNManager->GetListForBlock(v19_index);
|
||||
dummy_diff = v19_list.BuildDiff(tip_list);
|
||||
dummmy_list = v19_list.ApplyDiff(::ChainActive().Tip(), dummy_diff);
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
|
||||
// NOTE: this fails on v19/v19.1 with errors like:
|
||||
// "RemoveMN: Can't delete a masternode ... with a pubKeyOperator=..."
|
||||
dummy_diff = base_list.BuildDiff(tip_list);
|
||||
dummmy_list = base_list.ApplyDiff(::ChainActive().Tip(), dummy_diff);
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
|
||||
dummmy_list = base_list;
|
||||
for (const auto& diff : diffs) {
|
||||
dummmy_list = dummmy_list.ApplyDiff(::ChainActive().Tip(), diff);
|
||||
}
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
};
|
||||
|
||||
void FuncDIP3Protx(TestChainSetup& setup)
|
||||
{
|
||||
CKey sporkKey;
|
||||
@ -481,7 +612,7 @@ void FuncTestMempoolReorg(TestChainSetup& setup)
|
||||
payload.nVersion = CProRegTx::GetVersion(!bls::bls_legacy_scheme);
|
||||
payload.addr = LookupNumeric("1.1.1.1", 1);
|
||||
payload.keyIDOwner = ownerKey.GetPubKey().GetID();
|
||||
payload.pubKeyOperator = operatorKey.GetPublicKey();
|
||||
payload.pubKeyOperator.Set(operatorKey.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
payload.keyIDVoting = ownerKey.GetPubKey().GetID();
|
||||
payload.scriptPayout = scriptPayout;
|
||||
|
||||
@ -550,7 +681,7 @@ void FuncTestMempoolDualProregtx(TestChainSetup& setup)
|
||||
CProRegTx payload;
|
||||
payload.addr = LookupNumeric("1.1.1.1", 2);
|
||||
payload.keyIDOwner = ownerKey.GetPubKey().GetID();
|
||||
payload.pubKeyOperator = operatorKey.GetPublicKey();
|
||||
payload.pubKeyOperator.Set(operatorKey.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
payload.keyIDVoting = ownerKey.GetPubKey().GetID();
|
||||
payload.scriptPayout = scriptPayout;
|
||||
|
||||
@ -612,7 +743,7 @@ void FuncVerifyDB(TestChainSetup& setup)
|
||||
payload.nVersion = CProRegTx::GetVersion(!bls::bls_legacy_scheme);
|
||||
payload.addr = LookupNumeric("1.1.1.1", 1);
|
||||
payload.keyIDOwner = ownerKey.GetPubKey().GetID();
|
||||
payload.pubKeyOperator = operatorKey.GetPublicKey();
|
||||
payload.pubKeyOperator.Set(operatorKey.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
payload.keyIDVoting = ownerKey.GetPubKey().GetID();
|
||||
payload.scriptPayout = scriptPayout;
|
||||
|
||||
@ -667,6 +798,13 @@ BOOST_AUTO_TEST_CASE(dip3_activation_legacy)
|
||||
FuncDIP3Activation(setup);
|
||||
}
|
||||
|
||||
// V19 can only be activated with legacy scheme
|
||||
BOOST_AUTO_TEST_CASE(v19_activation_legacy)
|
||||
{
|
||||
TestChainV19BeforeActivationSetup setup;
|
||||
FuncV19Activation(setup);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dip3_protx_legacy)
|
||||
{
|
||||
TestChainDIP3Setup setup;
|
||||
|
@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots)
|
||||
std::vector<unsigned char> vecBytes{static_cast<unsigned char>(i)};
|
||||
vecBytes.resize(CBLSSecretKey::SerSize);
|
||||
|
||||
smle.pubKeyOperator.Set(CBLSSecretKey(vecBytes).GetPublicKey());
|
||||
smle.pubKeyOperator.Set(CBLSSecretKey(vecBytes).GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
smle.keyIDVoting.SetHex(strprintf("%040x", i));
|
||||
smle.isValid = true;
|
||||
|
||||
|
@ -29,14 +29,14 @@ void Test(llmq::CQuorumManager& qman)
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, qman, nullptr, true, false), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, qman, nullptr, true, true), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, nullptr, false, false), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, nullptr, false, false), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, nullptr, true, false), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, nullptr, true, true), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, nullptr, false, false), Params().IsTestChain());
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, nullptr, true, false), Params().IsTestChain());
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, nullptr, true, true), Params().IsTestChain());
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, nullptr, true, true), Params().IsTestChain());
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, nullptr, false, false), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, nullptr, true, false), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, nullptr, true, true), true);
|
||||
BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, nullptr, true, true), true);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(utils_IsQuorumTypeEnabled_tests_regtest, RegTestingSetup)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <llmq/signing_shares.h>
|
||||
#include <llmq/signing.h>
|
||||
#include <llmq/snapshot.h>
|
||||
#include <llmq/utils.h>
|
||||
#include <miner.h>
|
||||
#include <net.h>
|
||||
#include <net_processing.h>
|
||||
@ -391,3 +392,9 @@ CBlock getBlock13b8a()
|
||||
stream >> block;
|
||||
return block;
|
||||
}
|
||||
|
||||
TestChainV19BeforeActivationSetup::TestChainV19BeforeActivationSetup() : TestChainSetup(894)
|
||||
{
|
||||
bool v19_active = llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
assert(!v19_active);
|
||||
}
|
||||
|
@ -152,6 +152,11 @@ struct TestChainDIP3BeforeActivationSetup : public TestChainSetup
|
||||
TestChainDIP3BeforeActivationSetup() : TestChainSetup(430) {}
|
||||
};
|
||||
|
||||
struct TestChainV19BeforeActivationSetup : public TestChainSetup
|
||||
{
|
||||
TestChainV19BeforeActivationSetup();
|
||||
};
|
||||
|
||||
class CTxMemPoolEntry;
|
||||
|
||||
struct TestMemPoolEntryHelper
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <hash.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
#include <bls/bls.h>
|
||||
#include <evo/specialtx.h>
|
||||
#include <evo/providertx.h>
|
||||
#include <evo/deterministicmns.h>
|
||||
@ -443,7 +442,7 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash);
|
||||
assert(dmn);
|
||||
newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator);
|
||||
if (dmn->pdmnState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||
if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) {
|
||||
newit->isKeyChangeProTx = true;
|
||||
}
|
||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||
@ -838,7 +837,7 @@ void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID
|
||||
}
|
||||
}
|
||||
|
||||
void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey)
|
||||
void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSLazyPublicKey &pubKey)
|
||||
{
|
||||
if (mapProTxBlsPubKeyHashes.count(pubKey.GetHash())) {
|
||||
uint256 conflictHash = mapProTxBlsPubKeyHashes[pubKey.GetHash()];
|
||||
@ -1301,7 +1300,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
|
||||
return true; // i.e. failed to find validated ProTx == conflict
|
||||
}
|
||||
// only allow one operator key change in the mempool
|
||||
if (dmn->pdmnState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||
if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) {
|
||||
if (hasKeyChangeInMempool(proTx.proTxHash)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <addressindex.h>
|
||||
#include <spentindex.h>
|
||||
#include <amount.h>
|
||||
#include <bls/bls.h>
|
||||
#include <coins.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <indirectmap.h>
|
||||
@ -33,8 +34,6 @@
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
|
||||
class CBLSPublicKey;
|
||||
|
||||
class CBlockIndex;
|
||||
extern CCriticalSection cs_main;
|
||||
|
||||
@ -616,7 +615,7 @@ public:
|
||||
void removeForReorg(const CCoinsViewCache* pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID &keyId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSLazyPublicKey &pubKey) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxCollateralConflicts(const CTransaction &tx, const COutPoint &collateralOutpoint) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxSpentCollateralConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxKeyChangedConflicts(const CTransaction &tx, const uint256& proTxHash, const uint256& newKeyHash) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
@ -36,7 +36,6 @@ public:
|
||||
template<typename Value2>
|
||||
void _emplace(const Key& key, Value2&& v)
|
||||
{
|
||||
truncate_if_needed();
|
||||
auto it = cacheMap.find(key);
|
||||
if (it == cacheMap.end()) {
|
||||
cacheMap.emplace(key, std::make_pair(std::forward<Value2>(v), accessCounter++));
|
||||
@ -44,6 +43,7 @@ public:
|
||||
it->second.first = std::forward<Value2>(v);
|
||||
it->second.second = accessCounter++;
|
||||
}
|
||||
truncate_if_needed();
|
||||
}
|
||||
|
||||
void emplace(const Key& key, Value&& v)
|
||||
|
@ -4214,6 +4214,8 @@ bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhand
|
||||
AssertLockHeld(cs_main);
|
||||
assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
|
||||
|
||||
auto bls_legacy_scheme = bls::bls_legacy_scheme.load();
|
||||
|
||||
uint256 hash = block.GetHash();
|
||||
if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
|
||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock");
|
||||
@ -4240,6 +4242,12 @@ bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhand
|
||||
return false;
|
||||
assert(state.IsValid());
|
||||
|
||||
// we could switch to another scheme while testing, switch back to the original one
|
||||
if (bls_legacy_scheme != bls::bls_legacy_scheme.load()) {
|
||||
bls::bls_legacy_scheme.store(bls_legacy_scheme);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
|
||||
static const int PROTOCOL_VERSION = 70227;
|
||||
static const int PROTOCOL_VERSION = 70228;
|
||||
|
||||
//! initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
@ -53,6 +53,9 @@ static const int COINJOIN_PROTX_HASH_PROTO_VERSION = 70226;
|
||||
//! Masternode type was introduced in this version
|
||||
static const int DMN_TYPE_PROTO_VERSION = 70227;
|
||||
|
||||
//! Versioned Simplified Masternode List Entries were introduced in this version
|
||||
static const int SMNLE_VERSIONED_PROTO_VERSION = 70228;
|
||||
|
||||
// Make sure that none of the values above collide with `ADDRV2_FORMAT`.
|
||||
|
||||
#endif // BITCOIN_VERSION_H
|
||||
|
@ -620,7 +620,7 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||
|
||||
UniValue importelectrumwallet(const JSONRPCRequest& request)
|
||||
{
|
||||
RPCHelpMan{"importselectrumwallet",
|
||||
RPCHelpMan{"importelectrumwallet",
|
||||
"\nImports keys from an Electrum wallet export file (.csv or .json)\n",
|
||||
{
|
||||
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The Electrum wallet export file, should be in csv or json format"},
|
||||
|
@ -2864,7 +2864,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
|
||||
{
|
||||
{"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
|
||||
{"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
|
||||
{"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
|
||||
{"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using upgradetohd."},
|
||||
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
|
||||
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
|
||||
{"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
|
||||
|
@ -486,7 +486,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
strErr = "Found unsupported 'wkey' record, try loading with version 0.17";
|
||||
return false;
|
||||
} else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
|
||||
strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY && strType != DBKeys::VERSION) {
|
||||
strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
|
||||
strType != DBKeys::VERSION &&
|
||||
strType != DBKeys::PRIVATESEND_SALT && strType != DBKeys::COINJOIN_SALT) {
|
||||
wss.m_unknown_records++;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
|
@ -66,9 +66,18 @@ class DIP3V19Test(DashTestFramework):
|
||||
b_0 = self.nodes[0].getbestblockhash()
|
||||
self.test_getmnlistdiff(null_hash, b_0, {}, [], expected_updated)
|
||||
|
||||
mn_list_before = self.nodes[0].masternodelist()
|
||||
pubkeyoperator_list_before = set([mn_list_before[e]["pubkeyoperator"] for e in mn_list_before])
|
||||
|
||||
self.activate_v19(expected_activation_height=900)
|
||||
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))
|
||||
|
||||
mn_list_after = self.nodes[0].masternodelist()
|
||||
pubkeyoperator_list_after = set([mn_list_after[e]["pubkeyoperator"] for e in mn_list_after])
|
||||
|
||||
self.log.info("pubkeyoperator should still be shown using legacy scheme")
|
||||
assert_equal(pubkeyoperator_list_before, pubkeyoperator_list_after)
|
||||
|
||||
self.move_to_next_cycle()
|
||||
self.log.info("Cycle H height:" + str(self.nodes[0].getblockcount()))
|
||||
self.move_to_next_cycle()
|
||||
@ -101,8 +110,22 @@ class DIP3V19Test(DashTestFramework):
|
||||
self.test_revoke_protx(revoke_protx, revoke_keyoperator)
|
||||
|
||||
self.mine_quorum(llmq_type_name='llmq_test', llmq_type=100)
|
||||
# revoking a MN results in disconnects, reconnect it back to let sync_blocks finish correctly
|
||||
self.connect_nodes(hpmn_info_3.nodeIdx, 0)
|
||||
|
||||
return
|
||||
self.log.info("Checking that adding more regular MNs after v19 doesn't break DKGs and IS/CLs")
|
||||
|
||||
for i in range(6):
|
||||
new_mn = self.dynamically_add_masternode(hpmn=False, rnd=(10 + i))
|
||||
assert new_mn is not None
|
||||
|
||||
# mine more quorums and make sure everything still works
|
||||
prev_quorum = None
|
||||
for _ in range(5):
|
||||
quorum = self.mine_quorum()
|
||||
assert prev_quorum != quorum
|
||||
|
||||
self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash())
|
||||
|
||||
def test_revoke_protx(self, revoke_protx, revoke_keyoperator):
|
||||
funds_address = self.nodes[0].getnewaddress()
|
||||
@ -143,7 +166,7 @@ class DIP3V19Test(DashTestFramework):
|
||||
# Verify that the merkle root matches what we locally calculate
|
||||
hashes = []
|
||||
for mn in sorted(new_mn_list.values(), key=lambda mn: ser_uint256(mn.proRegTxHash)):
|
||||
hashes.append(hash256(mn.serialize()))
|
||||
hashes.append(hash256(mn.serialize(with_version = False)))
|
||||
merkle_root = CBlock.get_merkle_root(hashes)
|
||||
assert_equal(merkle_root, cbtx.merkleRootMNList)
|
||||
|
||||
|
@ -181,7 +181,7 @@ class LLMQCoinbaseCommitmentsTest(DashTestFramework):
|
||||
# Verify that the merkle root matches what we locally calculate
|
||||
hashes = []
|
||||
for mn in sorted(newMNList.values(), key=lambda mn: ser_uint256(mn.proRegTxHash)):
|
||||
hashes.append(hash256(mn.serialize()))
|
||||
hashes.append(hash256(mn.serialize(with_version = False)))
|
||||
merkleRoot = CBlock.get_merkle_root(hashes)
|
||||
assert_equal(merkleRoot, cbtx.merkleRootMNList)
|
||||
|
||||
|
@ -52,6 +52,20 @@ class LLMQChainLocksTest(DashTestFramework):
|
||||
block = self.nodes[0].getblock(self.nodes[0].getblockhash(h))
|
||||
assert block['chainlock']
|
||||
|
||||
# Update spork to SPORK_19_CHAINLOCKS_ENABLED and test its behaviour
|
||||
self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 1)
|
||||
self.wait_for_sporks_same()
|
||||
|
||||
# Generate new blocks and verify that they are not chainlocked
|
||||
previous_block_hash = self.nodes[0].getbestblockhash()
|
||||
for _ in range(2):
|
||||
block_hash = self.nodes[0].generate(1)[0]
|
||||
self.wait_for_chainlocked_block_all_nodes(block_hash, expected=False)
|
||||
assert self.nodes[0].getblock(previous_block_hash)["chainlock"]
|
||||
|
||||
self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 0)
|
||||
self.wait_for_sporks_same()
|
||||
|
||||
self.log.info("Isolate node, mine on another, and reconnect")
|
||||
self.isolate_node(0)
|
||||
node0_mining_addr = self.nodes[0].getnewaddress()
|
||||
|
@ -253,7 +253,7 @@ class LLMQHPMNTest(DashTestFramework):
|
||||
# Verify that the merkle root matches what we locally calculate
|
||||
hashes = []
|
||||
for mn in sorted(newMNList.values(), key=lambda mn: ser_uint256(mn.proRegTxHash)):
|
||||
hashes.append(hash256(mn.serialize()))
|
||||
hashes.append(hash256(mn.serialize(with_version = False)))
|
||||
merkleRoot = CBlock.get_merkle_root(hashes)
|
||||
assert_equal(merkleRoot, cbtx.merkleRootMNList)
|
||||
|
||||
|
@ -32,7 +32,7 @@ from test_framework.util import hex_str_to_bytes, assert_equal
|
||||
import dash_hash
|
||||
|
||||
MIN_VERSION_SUPPORTED = 60001
|
||||
MY_VERSION = 70227 # DMN_TYPE_PROTO_VERSION
|
||||
MY_VERSION = 70228 # SMNLE_VERSIONED_PROTO_VERSION
|
||||
MY_SUBVERSION = b"/python-mininode-tester:0.0.3%s/"
|
||||
MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)
|
||||
|
||||
@ -1078,7 +1078,7 @@ class CCbTx:
|
||||
|
||||
|
||||
class CSimplifiedMNListEntry:
|
||||
__slots__ = ("proRegTxHash", "confirmedHash", "service", "pubKeyOperator", "keyIDVoting", "isValid", "version", "type", "platformHTTPPort", "platformNodeID")
|
||||
__slots__ = ("proRegTxHash", "confirmedHash", "service", "pubKeyOperator", "keyIDVoting", "isValid", "nVersion", "type", "platformHTTPPort", "platformNodeID")
|
||||
|
||||
def __init__(self):
|
||||
self.set_null()
|
||||
@ -1090,34 +1090,36 @@ class CSimplifiedMNListEntry:
|
||||
self.pubKeyOperator = b'\x00' * 48
|
||||
self.keyIDVoting = 0
|
||||
self.isValid = False
|
||||
self.version = 0
|
||||
self.nVersion = 0
|
||||
self.type = 0
|
||||
self.platformHTTPPort = 0
|
||||
self.platformNodeID = b'\x00' * 20
|
||||
|
||||
def deserialize(self, f, version):
|
||||
self.version = version # memory only
|
||||
def deserialize(self, f):
|
||||
self.nVersion = struct.unpack("<H", f.read(2))[0]
|
||||
self.proRegTxHash = deser_uint256(f)
|
||||
self.confirmedHash = deser_uint256(f)
|
||||
self.service.deserialize(f)
|
||||
self.pubKeyOperator = f.read(48)
|
||||
self.keyIDVoting = f.read(20)
|
||||
self.isValid = struct.unpack("<?", f.read(1))[0]
|
||||
if self.version == 2:
|
||||
if self.nVersion == 2:
|
||||
self.type = struct.unpack("<H", f.read(2))[0]
|
||||
if self.type == 1:
|
||||
self.platformHTTPPort = struct.unpack("<H", f.read(2))[0]
|
||||
self.platformNodeID = f.read(20)
|
||||
|
||||
def serialize(self):
|
||||
def serialize(self, with_version = True):
|
||||
r = b""
|
||||
if with_version:
|
||||
r += struct.pack("<H", self.nVersion)
|
||||
r += ser_uint256(self.proRegTxHash)
|
||||
r += ser_uint256(self.confirmedHash)
|
||||
r += self.service.serialize()
|
||||
r += self.pubKeyOperator
|
||||
r += self.keyIDVoting
|
||||
r += struct.pack("<?", self.isValid)
|
||||
if self.version == 2:
|
||||
if self.nVersion == 2:
|
||||
r += struct.pack("<H", self.type)
|
||||
if self.type == 1:
|
||||
r += struct.pack("<H", self.platformHTTPPort)
|
||||
@ -1920,7 +1922,7 @@ class msg_getmnlistd:
|
||||
QuorumId = namedtuple('QuorumId', ['llmqType', 'quorumHash'])
|
||||
|
||||
class msg_mnlistdiff:
|
||||
__slots__ = ("baseBlockHash", "blockHash", "merkleProof", "cbTx", "version", "deletedMNs", "mnList", "deletedQuorums", "newQuorums",)
|
||||
__slots__ = ("baseBlockHash", "blockHash", "merkleProof", "cbTx", "nVersion", "deletedMNs", "mnList", "deletedQuorums", "newQuorums",)
|
||||
command = b"mnlistdiff"
|
||||
|
||||
def __init__(self):
|
||||
@ -1928,7 +1930,7 @@ class msg_mnlistdiff:
|
||||
self.blockHash = 0
|
||||
self.merkleProof = CPartialMerkleTree()
|
||||
self.cbTx = None
|
||||
self.version = 0
|
||||
self.nVersion = 0
|
||||
self.deletedMNs = []
|
||||
self.mnList = []
|
||||
self.deletedQuorums = []
|
||||
@ -1941,12 +1943,12 @@ class msg_mnlistdiff:
|
||||
self.cbTx = CTransaction()
|
||||
self.cbTx.deserialize(f)
|
||||
self.cbTx.rehash()
|
||||
self.version = struct.unpack("<H", f.read(2))[0]
|
||||
self.nVersion = struct.unpack("<H", f.read(2))[0]
|
||||
self.deletedMNs = deser_uint256_vector(f)
|
||||
self.mnList = []
|
||||
for i in range(deser_compact_size(f)):
|
||||
e = CSimplifiedMNListEntry()
|
||||
e.deserialize(f, self.version)
|
||||
e.deserialize(f)
|
||||
self.mnList.append(e)
|
||||
|
||||
self.deletedQuorums = []
|
||||
|
@ -1067,7 +1067,7 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
created_mn_info = self.dynamically_prepare_masternode(mn_idx, node_p2p_port, hpmn, rnd)
|
||||
protx_success = True
|
||||
except:
|
||||
self.log.info("protx_hpmn rejected")
|
||||
self.log.info("dynamically_prepare_masternode failed")
|
||||
|
||||
assert_equal(protx_success, not should_be_rejected)
|
||||
|
||||
@ -1083,7 +1083,7 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
|
||||
for mn_info in self.mninfo:
|
||||
if mn_info.proTxHash == created_mn_info.proTxHash:
|
||||
mn_info.nodeIx = mn_idx
|
||||
mn_info.nodeIdx = mn_idx
|
||||
mn_info.node = self.nodes[mn_idx]
|
||||
|
||||
self.connect_nodes(mn_idx, 0)
|
||||
@ -1104,8 +1104,8 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
reward_address = self.nodes[0].getnewaddress()
|
||||
|
||||
platform_node_id = hash160(b'%d' % rnd).hex() if rnd is not None else hash160(b'%d' % node_p2p_port).hex()
|
||||
platform_p2p_port = '%d' % (node_p2p_port + 101) if hpmn else ''
|
||||
platform_http_port = '%d' % (node_p2p_port + 102) if hpmn else ''
|
||||
platform_p2p_port = '%d' % (node_p2p_port + 101)
|
||||
platform_http_port = '%d' % (node_p2p_port + 102)
|
||||
|
||||
collateral_amount = 4000 if hpmn else 1000
|
||||
outputs = {collateral_address: collateral_amount, funds_address: 1}
|
||||
@ -1126,8 +1126,12 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
ipAndPort = '127.0.0.1:%d' % node_p2p_port
|
||||
operatorReward = idx
|
||||
|
||||
register_rpc = 'register_hpmn' if hpmn else 'register'
|
||||
protx_result = self.nodes[0].protx(register_rpc, collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, platform_node_id, platform_p2p_port, platform_http_port, funds_address, True)
|
||||
protx_result = None
|
||||
if hpmn:
|
||||
protx_result = self.nodes[0].protx("register_hpmn", collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, platform_node_id, platform_p2p_port, platform_http_port, funds_address, True)
|
||||
else:
|
||||
protx_result = self.nodes[0].protx("register", collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, funds_address, True)
|
||||
|
||||
self.wait_for_instantlock(protx_result, self.nodes[0])
|
||||
tip = self.nodes[0].generate(1)[0]
|
||||
self.sync_all(self.nodes)
|
||||
@ -1467,9 +1471,9 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
if wait_until(check_chainlocked_block, timeout=timeout, sleep=0.1, do_assert=expected) and not expected:
|
||||
raise AssertionError("waiting unexpectedly succeeded")
|
||||
|
||||
def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15):
|
||||
def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15, expected=True):
|
||||
for node in self.nodes:
|
||||
self.wait_for_chainlocked_block(node, block_hash, timeout=timeout)
|
||||
self.wait_for_chainlocked_block(node, block_hash, expected=expected, timeout=timeout)
|
||||
|
||||
def wait_for_best_chainlock(self, node, block_hash, timeout=15):
|
||||
wait_until(lambda: node.getbestchainlock()["blockhash"] == block_hash, timeout=timeout, sleep=0.1)
|
||||
|
Loading…
Reference in New Issue
Block a user