Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ class CMainParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nThresholdMin = 2420; // 60% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nFalloffCoeff = 5; // this corresponds to 10 periods

// Deployment of script addresses for Governance Proposals
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].bit = 7;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nStartTime = 1638316800; // Dec 1st, 2021
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nTimeout = 1669852800; // Dec 1st, 2022
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nWindowSize = 4032;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nThresholdStart = 3226; // 80% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nThresholdMin = 2420; // 60% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nFalloffCoeff = 5; // this corresponds to 10 periods

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000549cd3ccb81a55892330"); // 1450000

Expand Down Expand Up @@ -413,6 +422,15 @@ class CTestNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nThresholdMin = 60; // 60% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nFalloffCoeff = 5; // this corresponds to 10 periods

// Deployment of script addresses for Governance Proposals
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].bit = 7;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nStartTime = 1638316800; // Dec 1st, 2021
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nWindowSize = 4032;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nThresholdStart = 3226; // 80% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nThresholdMin = 60; // 60% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nFalloffCoeff = 5; // this corresponds to 10 periods

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000022f14ac5d56b5ef"); // 470000

Expand Down Expand Up @@ -595,6 +613,15 @@ class CDevNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nThresholdMin = 60; // 60% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nFalloffCoeff = 5; // this corresponds to 10 periods

// Deployment of script addresses for Governance Proposals
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].bit = 7;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nStartTime = 1638316800; // Dec 1st, 2021
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nWindowSize = 4032;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nThresholdStart = 3226; // 80% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nThresholdMin = 60; // 60% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nFalloffCoeff = 5; // this corresponds to 10 periods

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000000000000");

Expand Down Expand Up @@ -797,6 +824,9 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nThresholdStart = 80;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nThresholdMin = 60;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0020].nFalloffCoeff = 5;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].bit = 7;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_GOVSCRIPT].nTimeout = 999999999999ULL;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum DeploymentPos
DEPLOYMENT_DIP0008, // Deployment of ChainLock enforcement
DEPLOYMENT_REALLOC, // Deployment of Block Reward Reallocation
DEPLOYMENT_DIP0020, // Deployment of DIP0020, DIP0021 and LMQ_100_67 quorums
DEPLOYMENT_GOVSCRIPT, // Deployment of script addresses for Governance Proposals
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down
22 changes: 20 additions & 2 deletions src/governance/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ CGovernanceManager governance;

int nSubmittedFinalBudget;

const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-15";
const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-16";
const int CGovernanceManager::MAX_TIME_FUTURE_DEVIATION = 60 * 60;
const int CGovernanceManager::RELIABLE_PROPAGATION_TIME = 60;

Expand Down Expand Up @@ -427,7 +427,9 @@ void CGovernanceManager::UpdateCachesAndClean()
} else {
// NOTE: triggers are handled via triggerman
if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(pObj->GetDataAsHexString(), true);
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
bool fAllowLegacyFormat = !fAllowScript; // reusing the same bit to stop accepting proposals in legacy format
CProposalValidator validator(pObj->GetDataAsHexString(), fAllowLegacyFormat, fAllowScript);
if (!validator.Validate()) {
LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", strHash);
pObj->PrepareDeletion(nNow);
Expand Down Expand Up @@ -687,6 +689,22 @@ void CGovernanceManager::SyncObjects(CNode* pnode, CConnman& connman) const
continue;
}

if (pnode->nVersion < GOVSCRIPT_PROTO_VERSION && govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
// We know this proposal is valid locally, otherwise we would not store it.
// But we don't want to relay it to pre-GOVSCRIPT_PROTO_VERSION peers if payment_address is p2sh
// because they won't accept it anyway and will simply ban us eventually.
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
if (fAllowScript) {
CProposalValidator validator(govobj.GetDataAsHexString(), false /* no legacy format */, false /* but also no script */);
if (!validator.Validate(false /* ignore expiration */)) {
// The only way we could get here is when proposal is valid but payment_address is actually p2sh.
LogPrintf("CGovernanceManager::%s -- not syncing p2sh govobj to older node: %s, peer=%d\n", __func__,
strHash, pnode->GetId());
continue;
}
}
}

// Push the inventory budget proposal message over to the other client
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing govobj: %s, peer=%d\n", __func__, strHash, pnode->GetId());
pnode->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, nHash));
Expand Down
25 changes: 23 additions & 2 deletions src/governance/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool fCheckCollate

bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingConfirmations, bool fCheckCollateral) const
{
AssertLockHeld(cs_main);

fMissingConfirmations = false;

if (fUnparsable) {
Expand All @@ -462,7 +464,9 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingConf

switch (nObjectType) {
case GOVERNANCE_OBJECT_PROPOSAL: {
CProposalValidator validator(GetDataAsHexString(), true);
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
bool fAllowLegacyFormat = !fAllowScript; // reusing the same bit to stop accepting proposals in legacy format
CProposalValidator validator(GetDataAsHexString(), fAllowLegacyFormat, fAllowScript);
// Note: It's ok to have expired proposals
// they are going to be cleared by CGovernanceManager::UpdateCachesAndClean()
// TODO: should they be tagged as "expired" to skip vote downloading?
Expand Down Expand Up @@ -669,8 +673,25 @@ void CGovernanceObject::Relay(CConnman& connman) const
return;
}

int minProtoVersion = MIN_GOVERNANCE_PEER_PROTO_VERSION;
if (nObjectType == GOVERNANCE_OBJECT_PROPOSAL) {
// We know this proposal is valid locally, otherwise we would not get to the point we should relay it.
// But we don't want to relay it to pre-GOVSCRIPT_PROTO_VERSION peers if payment_address is p2sh
// because they won't accept it anyway and will simply ban us eventually.
LOCK(cs_main);
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
if (fAllowScript) {
CProposalValidator validator(GetDataAsHexString(), false /* no legacy format */, false /* but also no script */);
if (!validator.Validate(false /* ignore expiration */)) {
// The only way we could get here is when proposal is valid but payment_address is actually p2sh.
LogPrint(BCLog::GOBJECT, "CGovernanceObject::Relay -- won't relay %s to older peers\n", GetHash().ToString());
minProtoVersion = GOVSCRIPT_PROTO_VERSION;
}
}
}

CInv inv(MSG_GOVERNANCE_OBJECT, GetHash());
connman.RelayInv(inv, MIN_GOVERNANCE_PEER_PROTO_VERSION);
connman.RelayInv(inv, minProtoVersion);
}

void CGovernanceObject::UpdateSentinelVariables()
Expand Down
5 changes: 3 additions & 2 deletions src/governance/validators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
const size_t MAX_DATA_SIZE = 512;
const size_t MAX_NAME_SIZE = 40;

CProposalValidator::CProposalValidator(const std::string& strHexData, bool fAllowLegacyFormat) :
CProposalValidator::CProposalValidator(const std::string& strHexData, bool fAllowLegacyFormat, bool fAllowScript) :
objJSON(UniValue::VOBJ),
fJSONValid(false),
fAllowLegacyFormat(fAllowLegacyFormat),
fAllowScript(fAllowScript),
strErrorMessages()
{
if (!strHexData.empty()) {
Expand Down Expand Up @@ -180,7 +181,7 @@ bool CProposalValidator::ValidatePaymentAddress()
}

const CScriptID *scriptID = boost::get<CScriptID>(&dest);
if (scriptID) {
if (!fAllowScript && scriptID) {
strErrorMessages += "script addresses are not supported;";
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion src/governance/validators.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ class CProposalValidator
UniValue objJSON;
bool fJSONValid;
bool fAllowLegacyFormat;
bool fAllowScript;
std::string strErrorMessages;

public:
explicit CProposalValidator(const std::string& strDataHexIn = std::string(), bool fAllowLegacyFormat = true);
explicit CProposalValidator(const std::string& strDataHexIn = std::string(), bool fAllowLegacyFormat = true, bool fAllowScript = false);

bool Validate(bool fCheckExpiration = true);

Expand Down
15 changes: 12 additions & 3 deletions src/rpc/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ static UniValue gobject_check(const JSONRPCRequest& request)
CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strDataHex);

if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(strDataHex, false);
LOCK(cs_main);
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
// Note: we do not allow legacy format in RPC already, no need to reuse DEPLOYMENT_GOVSCRIPT
CProposalValidator validator(strDataHex, false, fAllowScript);
if (!validator.Validate()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
}
Expand Down Expand Up @@ -177,7 +180,10 @@ static UniValue gobject_prepare(const JSONRPCRequest& request)
govobj.GetDataAsPlainString(), govobj.GetHash().ToString());

if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(strDataHex, false);
LOCK(cs_main);
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
// Note: we do not allow legacy format in RPC already, no need to reuse DEPLOYMENT_GOVSCRIPT
CProposalValidator validator(strDataHex, false, fAllowScript);
if (!validator.Validate()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
}
Expand Down Expand Up @@ -342,7 +348,10 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
govobj.GetDataAsPlainString(), govobj.GetHash().ToString(), txidFee.ToString());

if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(strDataHex, false);
LOCK(cs_main);
bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOVSCRIPT) == ThresholdState::ACTIVE);
// Note: we do not allow legacy format in RPC already, no need to reuse DEPLOYMENT_GOVSCRIPT
CProposalValidator validator(strDataHex, false, fAllowScript);
if (!validator.Validate()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
}
Expand Down
1 change: 1 addition & 0 deletions src/test/data/proposals_invalid.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "yYe8KwyaUu5YswSYmB3q3ryx8XTUu9y7Ui", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": " XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "7V11XGPxzBWxkiuw15a1Vgk7XT74tyYtCY", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc ", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": " dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean miller 5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
Expand Down
29 changes: 24 additions & 5 deletions src/test/data/proposals_valid.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.12345678, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentralisé.org/dean-miller-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentralisé.org/dean-миллер-5493"},
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:/foo/"}
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
false
],
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "7V11XGPxzBWxkiuw15a1Vgk7XT74tyYtCY", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
true
],
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.12345678, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentral.org/dean-miller-5493"},
false
],
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentralisé.org/dean-miller-5493"},
false
],
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://dashcentralisé.org/dean-миллер-5493"},
false
],
[
{"end_epoch": 1491368400, "name": "dean-miller-5493", "payment_address": "XpG61qAVhdyN7AqVZQsHfJL7AEk4dPVinc", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:/foo/"},
false
]
]
13 changes: 7 additions & 6 deletions src/test/governance_validators_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,23 @@ BOOST_AUTO_TEST_CASE(valid_proposals_test)

BOOST_CHECK_MESSAGE(tests.size(), "Empty `tests`");
for(size_t i = 0; i < tests.size(); ++i) {
const UniValue& objProposal = tests[i];
const UniValue& objProposal = tests[i][0];
bool fAllowScript = tests[i][1].get_bool();

// legacy format
std::string strHexData1 = CreateEncodedProposalObject(objProposal);
CProposalValidator validator1(strHexData1, true);
CProposalValidator validator1(strHexData1, true, fAllowScript);
BOOST_CHECK_MESSAGE(validator1.Validate(false), validator1.GetErrorMessages());
BOOST_CHECK_MESSAGE(!validator1.Validate(), validator1.GetErrorMessages());

// legacy format w/validation flag off
CProposalValidator validator0(strHexData1, false);
CProposalValidator validator0(strHexData1, false, fAllowScript);
BOOST_CHECK(!validator0.Validate());
BOOST_CHECK_EQUAL(validator0.GetErrorMessages(), "Legacy proposal serialization format not allowed;JSON parsing error;");

// new format
std::string strHexData2 = HexStr(objProposal.write());
CProposalValidator validator2(strHexData2, false);
CProposalValidator validator2(strHexData2, false, fAllowScript);
BOOST_CHECK_MESSAGE(validator2.Validate(false), validator2.GetErrorMessages());
BOOST_CHECK_MESSAGE(!validator2.Validate(), validator2.GetErrorMessages());
}
Expand All @@ -74,12 +75,12 @@ BOOST_AUTO_TEST_CASE(invalid_proposals_test)

// legacy format
std::string strHexData1 = CreateEncodedProposalObject(objProposal);
CProposalValidator validator1(strHexData1, true);
CProposalValidator validator1(strHexData1, true, false);
BOOST_CHECK_MESSAGE(!validator1.Validate(false), validator1.GetErrorMessages());

// new format
std::string strHexData2 = HexStr(objProposal.write());
CProposalValidator validator2(strHexData2, false);
CProposalValidator validator2(strHexData2, false, false);
BOOST_CHECK_MESSAGE(!validator2.Validate(false), validator2.GetErrorMessages());
}
}
Expand Down
Loading