diff --git a/configure.ac b/configure.ac index 0b0d93d266bc..3b534ba2db2b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.69]) define(_CLIENT_VERSION_MAJOR, 3) define(_CLIENT_VERSION_MINOR, 4) define(_CLIENT_VERSION_REVISION, 2) -define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_BUILD, 11) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2023) diff --git a/doc/build-unix.md b/doc/build-unix.md index a256fa10cc2e..aa4b6bb186cf 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -13,7 +13,7 @@ Run the following commands to install required packages: ##### Debian/Ubuntu: ```bash -$ sudo apt-get install curl build-essential libtool autotools-dev automake pkg-config python3 bsdmainutils +$ sudo apt-get install curl build-essential libtool autotools-dev automake pkg-config python3 bsdmainutils libevent-dev libgmp-dev ``` ##### Fedora: @@ -158,4 +158,4 @@ If your user is in the `staff` group the limit can be raised with: The change will only affect the current shell and processes spawned by it. To make the change system-wide, change `datasize-cur` and `datasize-max` in -`/etc/login.conf`, and reboot. \ No newline at end of file +`/etc/login.conf`, and reboot. diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 21f7eebe95d2..1fec9d4d2309 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -108,6 +108,7 @@ static CBlock FindDevNetGenesisBlock(const CBlock &prevBlock, const CAmount& rew // iteration of the above loop will give a result already error("FindDevNetGenesisBlock: could not find devnet genesis block for %s", devNetName); assert(false); + return block; } void CChainParams::AddLLMQ(Consensus::LLMQType llmqType) @@ -344,9 +345,23 @@ class CMainParams : public CChainParams { nPoolMaxParticipants = 5; nFulfilledRequestExpireTime = 60*60; // fulfilled requests expire in 1 hour - vSporkAddressesV1 = {"sJbcSRccZQfmgjeW28uEEh9PswngZj1RXb"}; - vSporkAddressesV2 = {"sRSMpxfoejLYu7Y7Jd44MPfK76ap6cnXUR"}; - nMinSporkKeys = 1; + vSporkAddressesV1 = { + "sJbcSRccZQfmgjeW28uEEh9PswngZj1RXb" // o + }; + vSporkAddressesV2 = { + "sJbcSRccZQfmgjeW28uEEh9PswngZj1RXb", // o + "sRSMpxfoejLYu7Y7Jd44MPfK76ap6cnXUR", // c + "seHPSLpCmMxTKLSeaBaAvEMZgyk39xCA3q", // s + "sMXHsSGHCVJAfsebfs3g3g1hRcTioWTjBo" // d + }; + vSporkAddressesV3 = { + "sRSMpxfoejLYu7Y7Jd44MPfK76ap6cnXUR", // c + "seHPSLpCmMxTKLSeaBaAvEMZgyk39xCA3q", // s + "sMXHsSGHCVJAfsebfs3g3g1hRcTioWTjBo" // d + }; + nMinSporkKeysV1 = 1; + nMinSporkKeysV3 = 2; + fBIP9CheckMasternodesUpgraded = true; /** @@ -410,16 +425,17 @@ class CMainParams : public CChainParams { {700000, uint256S("000000000361299a95ea6a73d9a202a94893b3ec4fb441330740e20f9748cf36")}, {703355, uint256S("0000000002354cfaeb716435d7cfa632651f32ea22ef9796d25b893e264b2ea5")}, {703363, uint256S("00000000013b1c713a1ae71e6328f0f21efa08c7b8432d40bce681e4588645c4")}, - // 2023/09 - {717100, uint256S("0000000003189edcd28335b5e8bbb00752bad82c01c87604f4614ef103b14b24")} + // 2023/10 + {750001, uint256S("00000000006ed565d981c2ba21d19fd1b655847fa156e8a1da4647a33bbb5b74")}, + {750222, uint256S("000000000106b46906143c81532016eb1dcccf9859f3e1fc4f249c797f0c36ac")} } }; chainTxData = ChainTxData{ - 1692077442, // * UNIX timestamp of last known number of transactions (Block 1) - 703363, // * total number of transactions between genesis and that timestamp + 1697678866, // * UNIX timestamp of last known number of transactions (Block 750222) + 1498527, // * total number of transactions between genesis and that timestamp // (the tx=... number in the SetBestChain debug.log lines) - 0.0153 // * estimated number of transactions per second after that timestamp + 0.0208 // * estimated number of transactions per second after that timestamp }; } }; @@ -589,8 +605,10 @@ class CTestNetParams : public CChainParams { nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes vSporkAddressesV1 = {"yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55"}; - vSporkAddressesV2 = {"yaBHHsZP4MthVVexFXiLgzUw7mwzxY9KRF"}; - nMinSporkKeys = 1; + vSporkAddressesV2 = {"yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55", "yaBHHsZP4MthVVexFXiLgzUw7mwzxY9KRF"}; + vSporkAddressesV3 = {"yaBHHsZP4MthVVexFXiLgzUw7mwzxY9KRF"}; + nMinSporkKeysV1 = 1; + nMinSporkKeysV3 = 1; fBIP9CheckMasternodesUpgraded = true; checkpointData = { @@ -778,9 +796,11 @@ class CDevNetParams : public CChainParams { nPoolMaxParticipants = 20; nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes - vSporkAddressesV1 = {"yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55"}; + vSporkAddressesV1 = {"yaBHHsZP4MthVVexFXiLgzUw7mwzxY9KRF"}; vSporkAddressesV2 = {"yaBHHsZP4MthVVexFXiLgzUw7mwzxY9KRF"}; - nMinSporkKeys = 1; + vSporkAddressesV3 = {"yaBHHsZP4MthVVexFXiLgzUw7mwzxY9KRF"}; + nMinSporkKeysV1 = 1; + nMinSporkKeysV3 = 1; // devnets are started with no blocks and no MN, so we can't check for upgraded MN (as there are none) fBIP9CheckMasternodesUpgraded = false; @@ -959,7 +979,9 @@ class CRegTestParams : public CChainParams { // privKey: cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK vSporkAddressesV1 = {"yj949n1UH6fDhw6HtVE5VMj2iSTaSWBMcW"}; vSporkAddressesV2 = {"yj949n1UH6fDhw6HtVE5VMj2iSTaSWBMcW"}; - nMinSporkKeys = 1; + vSporkAddressesV3 = {"yj949n1UH6fDhw6HtVE5VMj2iSTaSWBMcW"}; + nMinSporkKeysV1 = 1; + nMinSporkKeysV3 = 1; // regtest usually has no masternodes in most tests, so don't check for upgraged MNs fBIP9CheckMasternodesUpgraded = false; diff --git a/src/chainparams.h b/src/chainparams.h index f4e1cac55d7c..f72966d55a18 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -108,7 +108,9 @@ class CChainParams int FulfilledRequestExpireTime() const { return nFulfilledRequestExpireTime; } const std::vector& SporkAddressesV1() const { return vSporkAddressesV1; } const std::vector& SporkAddressesV2() const { return vSporkAddressesV2; } - int MinSporkKeys() const { return nMinSporkKeys; } + const std::vector& SporkAddressesV3() const { return vSporkAddressesV3; } + int MinSporkKeysV1() const { return nMinSporkKeysV1; } + int MinSporkKeysV3() const { return nMinSporkKeysV3; } bool BIP9CheckMasternodesUpgraded() const { return fBIP9CheckMasternodesUpgraded; } const Consensus::LLMQParams& GetLLMQ(Consensus::LLMQType llmqType) const; bool HasLLMQ(Consensus::LLMQType llmqType) const; @@ -144,7 +146,9 @@ class CChainParams int nFulfilledRequestExpireTime; std::vector vSporkAddressesV1; std::vector vSporkAddressesV2; - int nMinSporkKeys; + std::vector vSporkAddressesV3; + int nMinSporkKeysV1; + int nMinSporkKeysV3; bool fBIP9CheckMasternodesUpgraded; void AddLLMQ(Consensus::LLMQType llmqType); diff --git a/src/init.cpp b/src/init.cpp index 65b72c4e5204..c4275a0e28e2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1685,7 +1685,7 @@ bool AppInitMain(InitInterfaces& interfaces) if (gArgs.IsArgSet("-sporkaddr")) { vSporkAddresses = gArgs.GetArgs("-sporkaddr"); } else { - vSporkAddresses = Params().SporkAddressesV1(); + vSporkAddresses = chainparams.SporkAddressesV1(); } for (const auto& address: vSporkAddresses) { if (!sporkManager.SetSporkAddress(address)) { @@ -1693,12 +1693,11 @@ bool AppInitMain(InitInterfaces& interfaces) } } - int minsporkkeys = gArgs.GetArg("-minsporkkeys", Params().MinSporkKeys()); + int minsporkkeys = gArgs.GetArg("-minsporkkeys", chainparams.MinSporkKeysV1()); if (!sporkManager.SetMinSporkKeys(minsporkkeys)) { return InitError(_("Invalid minimum number of spork signers specified with -minsporkkeys").translated); } - if (gArgs.IsArgSet("-sporkkey")) { // spork priv key if (!sporkManager.SetPrivKey(gArgs.GetArg("-sporkkey", ""))) { return InitError(_("Unable to sign spork message, wrong key?").translated); @@ -2492,12 +2491,19 @@ bool AppInitMain(InitInterfaces& interfaces) // ********************************************************* Step 12.1: uprade sporks - if (chain_active_height >= 750000 && chainparams.NetworkIDString() == CBaseChainParams::MAIN) { + if (chain_active_height < sporkManager.getNewSporkLockHeight()) { + LogPrintf("[init] CSporkManager -- Spork V3 Activation Height: %d Lock Height: %d\n", sporkManager.getNewSporkActHeight(), sporkManager.getNewSporkLockHeight()); + } + if (chain_active_height >= sporkManager.getNewSporkActHeight() && chainparams.NetworkIDString() == CBaseChainParams::MAIN) { std::vector vSporkAddresses; if (gArgs.IsArgSet("-sporkaddr")) { vSporkAddresses = gArgs.GetArgs("-sporkaddr"); + } else if (chain_active_height >= sporkManager.getNewSporkLockHeight()) { + vSporkAddresses = Params().SporkAddressesV3(); + LogPrintf("Using V3 Spork Addresses\n"); } else { vSporkAddresses = Params().SporkAddressesV2(); + LogPrintf("Using V2 Spork Addresses\n"); } sporkManager.ClearSporkAddresses(); for (const auto& address : vSporkAddresses) { @@ -2505,22 +2511,16 @@ bool AppInitMain(InitInterfaces& interfaces) return InitError(_("Invalid spork address specified with -sporkaddr").translated); } } - LogPrintf("Using V2 Spork Addresses\n"); - } - if (chain_active_height >= 7500 && chainparams.NetworkIDString() == CBaseChainParams::TESTNET) { - std::vector vSporkAddresses; - if (gArgs.IsArgSet("-sporkaddr")) { - vSporkAddresses = gArgs.GetArgs("-sporkaddr"); - } else { - vSporkAddresses = Params().SporkAddressesV2(); + if (!gArgs.IsArgSet("-sporkaddr")) { + if (!sporkManager.CheckSporkPubkeyIDs()) { + LogPrintf("CSporkManager -- WARN: mismatched spork addresses have been updated!\n"); + } } - sporkManager.ClearSporkAddresses(); - for (const auto& address : vSporkAddresses) { - if (!sporkManager.SetSporkAddress(address)) { - return InitError(_("Invalid spork address specified with -sporkaddr").translated); + if (chain_active_height >= sporkManager.getNewSporkLockHeight()) { + if (!sporkManager.SetMinSporkKeys(Params().MinSporkKeysV3())) { + return InitError(_("Invalid minimum number of spork signers specified for V3!").translated); } } - LogPrintf("Using V2 Spork Addresses\n"); } // ********************************************************* Step 13: finished diff --git a/src/spork.cpp b/src/spork.cpp index 9c66bb52e175..aa35fa52ad66 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -101,6 +101,9 @@ void CSporkManager::CheckAndRemove() void CSporkManager::ProcessSporkMessages(CNode* pfrom, std::string_view strCommand, CDataStream& vRecv, CConnman& connman) { + if (!CheckSporkPubkeyIDs()) { + LogPrintf("CSporkManager::ProcessSporkMessages -- WARN: updated mismatching spork addresses\n"); + } ProcessSpork(pfrom, strCommand, vRecv, connman); ProcessGetSporks(pfrom, strCommand, connman); } @@ -134,7 +137,11 @@ void CSporkManager::ProcessSpork(const CNode* pfrom, std::string_view strCommand if (!spork.GetSignerKeyID(keyIDSigner) || WITH_LOCK(cs, return !setSporkPubKeyIDs.count(keyIDSigner))) { LOCK(cs_main); LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: invalid signature\n"); - Misbehaving(pfrom->GetId(), 100); + + int nHeight = ::ChainActive().Tip()->nHeight; + if (nHeight > nNewSporkLockHeight) { + Misbehaving(pfrom->GetId(), 100); + } return; } @@ -329,6 +336,65 @@ bool CSporkManager::SetPrivKey(const std::string& strPrivKey) return true; } +bool CSporkManager::CheckSporkPubkeyIDs() +{ + const CChainParams& params = Params(); + if (!::ChainActive().Tip() || params.NetworkIDString() != CBaseChainParams::MAIN) + { + return true; + } + + int nHeight = ::ChainActive().Tip()->nHeight; + if (nHeight > nNewSporkLockHeight) { + // change completed. spork changes locked. + return true; + } + + if (nHeight >= nNewSporkActHeight) { // start of checks + std::vector vSporkAddresses = params.SporkAddressesV2(); + bool fLocking = false; + bool matches = true; + int nFound = 0; + if (nHeight >= nNewSporkLockHeight - 200) { // act shortly before lockout + vSporkAddresses = params.SporkAddressesV3(); + fLocking = true; + } + LOCK(cs); + for (const auto& strAddress : vSporkAddresses) { + CTxDestination dest = DecodeDestination(strAddress); + const CKeyID* keyID = boost::get(&dest); + if (!keyID) { + LogPrintf("CSporkManager::CheckSporkPubkeyIDs -- Failed to parse spork address\n"); + matches = false; + } else if (setSporkPubKeyIDs.find(*keyID) == setSporkPubKeyIDs.end()) { + LogPrintf("CSporkManager::CheckSporkPubkeyIDs -- WARN: spork address %s not found\n", strAddress); + matches = false; + } else { + nFound++; + } + } + if (nFound != setSporkPubKeyIDs.size()) { + LogPrintf("CSporkManager::CheckSporkPubkeyIDs -- WARN: spork address set length mismatch\n"); + matches = false; + } + if (!matches) { + sporkManager.ClearSporkAddresses(); + for (const auto& address : vSporkAddresses) { + if (!sporkManager.SetSporkAddress(address)) { + LogPrintf("CSporkManager::CheckSporkPubkeyIDs -- ERROR: invalid spork address\n"); + } + } + if (fLocking) { + nMinSporkKeys = params.MinSporkKeysV3(); + } else { + nMinSporkKeys = params.MinSporkKeysV1(); + } + return false; + } + } + return true; +} + std::string CSporkManager::ToString() const { LOCK(cs); diff --git a/src/spork.h b/src/spork.h index 0798fdd29f3f..4061dcc526e0 100644 --- a/src/spork.h +++ b/src/spork.h @@ -180,6 +180,9 @@ class CSporkManager */ bool SporkValueIsActive(SporkId nSporkID, int64_t& nActiveValueRet) const EXCLUSIVE_LOCKS_REQUIRED(cs); + int nNewSporkActHeight = 755040; + int nNewSporkLockHeight = 775200; + public: CSporkManager() = default; @@ -317,6 +320,19 @@ class CSporkManager */ bool SetPrivKey(const std::string& strPrivKey); + /** + * CheckSporkPubkeyIDs is used to check the pubkeys for spork signers + * match the expected. Will update the list if there is mismatching. + * + * This will return true if there are no mismatches. + */ + bool CheckSporkPubkeyIDs(); + + /* Gets height the new sporks should become active. */ + int getNewSporkActHeight() { return nNewSporkActHeight; }; + /* Gets height the new sporks should lock. Used for ban control. */ + int getNewSporkLockHeight() { return nNewSporkLockHeight; }; + /** * ToString returns the string representation of the SporkManager. */