Disallow new proposals using legacy serialization (#2722)

*  add flag to allow legacy proposal format

* add proposal validator ctor flag for legacy format

* add test for legacy proposal format disabled
This commit is contained in:
Nathan Marley 2019-02-26 07:44:43 -03:00 committed by UdjinM6
parent 668b84b1e4
commit fcd3b4fd49
6 changed files with 25 additions and 14 deletions

View File

@ -469,7 +469,7 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
return false; return false;
} }
case GOVERNANCE_OBJECT_PROPOSAL: { case GOVERNANCE_OBJECT_PROPOSAL: {
CProposalValidator validator(GetDataAsHexString()); CProposalValidator validator(GetDataAsHexString(), true);
// Note: It's ok to have expired proposals // Note: It's ok to have expired proposals
// they are going to be cleared by CGovernanceManager::UpdateCachesAndClean() // they are going to be cleared by CGovernanceManager::UpdateCachesAndClean()
// TODO: should they be tagged as "expired" to skip vote downloading? // TODO: should they be tagged as "expired" to skip vote downloading?

View File

@ -14,9 +14,10 @@
const size_t MAX_DATA_SIZE = 512; const size_t MAX_DATA_SIZE = 512;
const size_t MAX_NAME_SIZE = 40; const size_t MAX_NAME_SIZE = 40;
CProposalValidator::CProposalValidator(const std::string& strHexData) : CProposalValidator::CProposalValidator(const std::string& strHexData, bool fAllowLegacyFormat) :
objJSON(UniValue::VOBJ), objJSON(UniValue::VOBJ),
fJSONValid(false), fJSONValid(false),
fAllowLegacyFormat(fAllowLegacyFormat),
strErrorMessages() strErrorMessages()
{ {
if (!strHexData.empty()) { if (!strHexData.empty()) {
@ -207,9 +208,13 @@ void CProposalValidator::ParseJSONData(const std::string& strJSONData)
if (obj.isObject()) { if (obj.isObject()) {
objJSON = obj; objJSON = obj;
} else { } else {
std::vector<UniValue> arr1 = obj.getValues(); if (fAllowLegacyFormat) {
std::vector<UniValue> arr2 = arr1.at(0).getValues(); std::vector<UniValue> arr1 = obj.getValues();
objJSON = arr2.at(1); std::vector<UniValue> arr2 = arr1.at(0).getValues();
objJSON = arr2.at(1);
} else {
throw std::runtime_error("Legacy proposal serialization format not allowed");
}
} }
fJSONValid = true; fJSONValid = true;

View File

@ -14,10 +14,11 @@ class CProposalValidator
private: private:
UniValue objJSON; UniValue objJSON;
bool fJSONValid; bool fJSONValid;
bool fAllowLegacyFormat;
std::string strErrorMessages; std::string strErrorMessages;
public: public:
CProposalValidator(const std::string& strDataHexIn = std::string()); CProposalValidator(const std::string& strDataHexIn = std::string(), bool fAllowLegacyFormat = true);
bool Validate(bool fCheckExpiration = true); bool Validate(bool fCheckExpiration = true);

View File

@ -452,7 +452,7 @@ void CGovernanceManager::UpdateCachesAndClean()
} else { } else {
// NOTE: triggers are handled via triggerman // NOTE: triggers are handled via triggerman
if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(pObj->GetDataAsHexString()); CProposalValidator validator(pObj->GetDataAsHexString(), true);
if (!validator.Validate()) { if (!validator.Validate()) {
LogPrintf("CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", (*it).first.ToString()); LogPrintf("CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", (*it).first.ToString());
pObj->fCachedDelete = true; pObj->fCachedDelete = true;

View File

@ -102,7 +102,7 @@ UniValue gobject_check(const JSONRPCRequest& request)
CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strDataHex); CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strDataHex);
if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(strDataHex); CProposalValidator validator(strDataHex, false);
if (!validator.Validate()) { if (!validator.Validate()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
} }
@ -176,7 +176,7 @@ UniValue gobject_prepare(const JSONRPCRequest& request)
govobj.GetDataAsPlainString(), govobj.GetHash().ToString()); govobj.GetDataAsPlainString(), govobj.GetHash().ToString());
if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(strDataHex); CProposalValidator validator(strDataHex, false);
if (!validator.Validate()) { if (!validator.Validate()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
} }
@ -297,7 +297,7 @@ UniValue gobject_submit(const JSONRPCRequest& request)
<< std::endl; ); << std::endl; );
if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
CProposalValidator validator(strDataHex); CProposalValidator validator(strDataHex, false);
if (!validator.Validate()) { if (!validator.Validate()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages());
} }

View File

@ -45,13 +45,18 @@ BOOST_AUTO_TEST_CASE(valid_proposals_test)
// legacy format // legacy format
std::string strHexData1 = CreateEncodedProposalObject(objProposal); std::string strHexData1 = CreateEncodedProposalObject(objProposal);
CProposalValidator validator1(strHexData1); CProposalValidator validator1(strHexData1, true);
BOOST_CHECK_MESSAGE(validator1.Validate(false), validator1.GetErrorMessages()); BOOST_CHECK_MESSAGE(validator1.Validate(false), validator1.GetErrorMessages());
BOOST_CHECK_MESSAGE(!validator1.Validate(), validator1.GetErrorMessages()); BOOST_CHECK_MESSAGE(!validator1.Validate(), validator1.GetErrorMessages());
// legacy format w/validation flag off
CProposalValidator validator0(strHexData1, false);
BOOST_CHECK(!validator0.Validate());
BOOST_CHECK_EQUAL(validator0.GetErrorMessages(), "Legacy proposal serialization format not allowed;JSON parsing error;");
// new format // new format
std::string strHexData2 = HexStr(objProposal.write()); std::string strHexData2 = HexStr(objProposal.write());
CProposalValidator validator2(strHexData2); CProposalValidator validator2(strHexData2, false);
BOOST_CHECK_MESSAGE(validator2.Validate(false), validator2.GetErrorMessages()); BOOST_CHECK_MESSAGE(validator2.Validate(false), validator2.GetErrorMessages());
BOOST_CHECK_MESSAGE(!validator2.Validate(), validator2.GetErrorMessages()); BOOST_CHECK_MESSAGE(!validator2.Validate(), validator2.GetErrorMessages());
} }
@ -69,12 +74,12 @@ BOOST_AUTO_TEST_CASE(invalid_proposals_test)
// legacy format // legacy format
std::string strHexData1 = CreateEncodedProposalObject(objProposal); std::string strHexData1 = CreateEncodedProposalObject(objProposal);
CProposalValidator validator1(strHexData1); CProposalValidator validator1(strHexData1, true);
BOOST_CHECK_MESSAGE(!validator1.Validate(false), validator1.GetErrorMessages()); BOOST_CHECK_MESSAGE(!validator1.Validate(false), validator1.GetErrorMessages());
// new format // new format
std::string strHexData2 = HexStr(objProposal.write()); std::string strHexData2 = HexStr(objProposal.write());
CProposalValidator validator2(strHexData2); CProposalValidator validator2(strHexData2, false);
BOOST_CHECK_MESSAGE(!validator2.Validate(false), validator2.GetErrorMessages()); BOOST_CHECK_MESSAGE(!validator2.Validate(false), validator2.GetErrorMessages());
} }
} }