mirror of
https://github.com/dashpay/dash.git
synced 2024-12-29 05:49:11 +01:00
8a1ec935a0
* scripted-diff: Replace #include "" with #include <> (ryanofsky) -BEGIN VERIFY SCRIPT- for f in \ src/*.cpp \ src/*.h \ src/bench/*.cpp \ src/bench/*.h \ src/compat/*.cpp \ src/compat/*.h \ src/consensus/*.cpp \ src/consensus/*.h \ src/crypto/*.cpp \ src/crypto/*.h \ src/crypto/ctaes/*.h \ src/policy/*.cpp \ src/policy/*.h \ src/primitives/*.cpp \ src/primitives/*.h \ src/qt/*.cpp \ src/qt/*.h \ src/qt/test/*.cpp \ src/qt/test/*.h \ src/rpc/*.cpp \ src/rpc/*.h \ src/script/*.cpp \ src/script/*.h \ src/support/*.cpp \ src/support/*.h \ src/support/allocators/*.h \ src/test/*.cpp \ src/test/*.h \ src/wallet/*.cpp \ src/wallet/*.h \ src/wallet/test/*.cpp \ src/wallet/test/*.h \ src/zmq/*.cpp \ src/zmq/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * scripted-diff: Replace #include "" with #include <> (Dash Specific) -BEGIN VERIFY SCRIPT- for f in \ src/bls/*.cpp \ src/bls/*.h \ src/evo/*.cpp \ src/evo/*.h \ src/governance/*.cpp \ src/governance/*.h \ src/llmq/*.cpp \ src/llmq/*.h \ src/masternode/*.cpp \ src/masternode/*.h \ src/privatesend/*.cpp \ src/privatesend/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * build: Remove -I for everything but project root Remove -I from build system for everything but the project root, and built-in dependencies. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/Makefile.test.include * qt: refactor: Use absolute include paths in .ui files * qt: refactor: Changes to make include paths absolute This makes all include paths in the GUI absolute. Many changes are involved as every single source file in src/qt/ assumes to be able to use relative includes. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/qt/dash.cpp # src/qt/optionsmodel.cpp # src/qt/test/rpcnestedtests.cpp * test: refactor: Use absolute include paths for test data files * Recommend #include<> syntax in developer notes * refactor: Include obj/build.h instead of build.h * END BACKPORT #11651 Remove trailing whitespace causing travis failure * fix backport 11651 Signed-off-by: Pasta <pasta@dashboost.org> * More of 11651 * fix blockchain.cpp Signed-off-by: pasta <pasta@dashboost.org> * Add missing "qt/" in includes * Add missing "test/" in includes * Fix trailing whitespaces Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: Russell Yanofsky <russ@yanofsky.org> Co-authored-by: MeshCollider <dobsonsa68@gmail.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
327 lines
8.6 KiB
C++
327 lines
8.6 KiB
C++
// Copyright (c) 2014-2019 The Dash Core developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <governance/governance-validators.h>
|
|
|
|
#include <base58.h>
|
|
#include <timedata.h>
|
|
#include <tinyformat.h>
|
|
#include <utilstrencodings.h>
|
|
|
|
#include <algorithm>
|
|
|
|
const size_t MAX_DATA_SIZE = 512;
|
|
const size_t MAX_NAME_SIZE = 40;
|
|
|
|
CProposalValidator::CProposalValidator(const std::string& strHexData, bool fAllowLegacyFormat) :
|
|
objJSON(UniValue::VOBJ),
|
|
fJSONValid(false),
|
|
fAllowLegacyFormat(fAllowLegacyFormat),
|
|
strErrorMessages()
|
|
{
|
|
if (!strHexData.empty()) {
|
|
ParseStrHexData(strHexData);
|
|
}
|
|
}
|
|
|
|
void CProposalValidator::ParseStrHexData(const std::string& strHexData)
|
|
{
|
|
std::vector<unsigned char> v = ParseHex(strHexData);
|
|
if (v.size() > MAX_DATA_SIZE) {
|
|
strErrorMessages = strprintf("data exceeds %lu characters;", MAX_DATA_SIZE);
|
|
return;
|
|
}
|
|
ParseJSONData(std::string(v.begin(), v.end()));
|
|
}
|
|
|
|
bool CProposalValidator::Validate(bool fCheckExpiration)
|
|
{
|
|
if (!fJSONValid) {
|
|
strErrorMessages += "JSON parsing error;";
|
|
return false;
|
|
}
|
|
if (!ValidateName()) {
|
|
strErrorMessages += "Invalid name;";
|
|
return false;
|
|
}
|
|
if (!ValidateStartEndEpoch(fCheckExpiration)) {
|
|
strErrorMessages += "Invalid start:end range;";
|
|
return false;
|
|
}
|
|
if (!ValidatePaymentAmount()) {
|
|
strErrorMessages += "Invalid payment amount;";
|
|
return false;
|
|
}
|
|
if (!ValidatePaymentAddress()) {
|
|
strErrorMessages += "Invalid payment address;";
|
|
return false;
|
|
}
|
|
if (!ValidateURL()) {
|
|
strErrorMessages += "Invalid URL;";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CProposalValidator::ValidateName()
|
|
{
|
|
std::string strName;
|
|
if (!GetDataValue("name", strName)) {
|
|
strErrorMessages += "name field not found;";
|
|
return false;
|
|
}
|
|
|
|
if (strName.size() > MAX_NAME_SIZE) {
|
|
strErrorMessages += strprintf("name exceeds %lu characters;", MAX_NAME_SIZE);
|
|
return false;
|
|
}
|
|
|
|
static const std::string strAllowedChars = "-_abcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
|
std::transform(strName.begin(), strName.end(), strName.begin(), ::tolower);
|
|
|
|
if (strName.find_first_not_of(strAllowedChars) != std::string::npos) {
|
|
strErrorMessages += "name contains invalid characters;";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CProposalValidator::ValidateStartEndEpoch(bool fCheckExpiration)
|
|
{
|
|
int64_t nStartEpoch = 0;
|
|
int64_t nEndEpoch = 0;
|
|
|
|
if (!GetDataValue("start_epoch", nStartEpoch)) {
|
|
strErrorMessages += "start_epoch field not found;";
|
|
return false;
|
|
}
|
|
|
|
if (!GetDataValue("end_epoch", nEndEpoch)) {
|
|
strErrorMessages += "end_epoch field not found;";
|
|
return false;
|
|
}
|
|
|
|
if (nEndEpoch <= nStartEpoch) {
|
|
strErrorMessages += "end_epoch <= start_epoch;";
|
|
return false;
|
|
}
|
|
|
|
if (fCheckExpiration && nEndEpoch <= GetAdjustedTime()) {
|
|
strErrorMessages += "expired;";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CProposalValidator::ValidatePaymentAmount()
|
|
{
|
|
double dValue = 0.0;
|
|
|
|
if (!GetDataValue("payment_amount", dValue)) {
|
|
strErrorMessages += "payment_amount field not found;";
|
|
return false;
|
|
}
|
|
|
|
if (dValue <= 0.0) {
|
|
strErrorMessages += "payment_amount is negative;";
|
|
return false;
|
|
}
|
|
|
|
// TODO: Should check for an amount which exceeds the budget but this is
|
|
// currently difficult because start and end epochs are defined in terms of
|
|
// clock time instead of block height.
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CProposalValidator::ValidatePaymentAddress()
|
|
{
|
|
std::string strPaymentAddress;
|
|
|
|
if (!GetDataValue("payment_address", strPaymentAddress)) {
|
|
strErrorMessages += "payment_address field not found;";
|
|
return false;
|
|
}
|
|
|
|
if (std::find_if(strPaymentAddress.begin(), strPaymentAddress.end(), ::isspace) != strPaymentAddress.end()) {
|
|
strErrorMessages += "payment_address can't have whitespaces;";
|
|
return false;
|
|
}
|
|
|
|
CTxDestination dest = DecodeDestination(strPaymentAddress);
|
|
if (!IsValidDestination(dest)) {
|
|
strErrorMessages += "payment_address is invalid;";
|
|
return false;
|
|
}
|
|
|
|
const CScriptID *scriptID = boost::get<CScriptID>(&dest);
|
|
if (scriptID) {
|
|
strErrorMessages += "script addresses are not supported;";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CProposalValidator::ValidateURL()
|
|
{
|
|
std::string strURL;
|
|
if (!GetDataValue("url", strURL)) {
|
|
strErrorMessages += "url field not found;";
|
|
return false;
|
|
}
|
|
|
|
if (std::find_if(strURL.begin(), strURL.end(), ::isspace) != strURL.end()) {
|
|
strErrorMessages += "url can't have whitespaces;";
|
|
return false;
|
|
}
|
|
|
|
if (strURL.size() < 4U) {
|
|
strErrorMessages += "url too short;";
|
|
return false;
|
|
}
|
|
|
|
if (!CheckURL(strURL)) {
|
|
strErrorMessages += "url invalid;";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CProposalValidator::ParseJSONData(const std::string& strJSONData)
|
|
{
|
|
fJSONValid = false;
|
|
|
|
if (strJSONData.empty()) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
UniValue obj(UniValue::VOBJ);
|
|
|
|
obj.read(strJSONData);
|
|
|
|
if (obj.isObject()) {
|
|
objJSON = obj;
|
|
} else {
|
|
if (fAllowLegacyFormat) {
|
|
std::vector<UniValue> arr1 = obj.getValues();
|
|
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;
|
|
} catch (std::exception& e) {
|
|
strErrorMessages += std::string(e.what()) + std::string(";");
|
|
} catch (...) {
|
|
strErrorMessages += "Unknown exception;";
|
|
}
|
|
}
|
|
|
|
bool CProposalValidator::GetDataValue(const std::string& strKey, std::string& strValueRet)
|
|
{
|
|
bool fOK = false;
|
|
try {
|
|
strValueRet = objJSON[strKey].get_str();
|
|
fOK = true;
|
|
} catch (std::exception& e) {
|
|
strErrorMessages += std::string(e.what()) + std::string(";");
|
|
} catch (...) {
|
|
strErrorMessages += "Unknown exception;";
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
bool CProposalValidator::GetDataValue(const std::string& strKey, int64_t& nValueRet)
|
|
{
|
|
bool fOK = false;
|
|
try {
|
|
const UniValue uValue = objJSON[strKey];
|
|
switch (uValue.getType()) {
|
|
case UniValue::VNUM:
|
|
nValueRet = uValue.get_int64();
|
|
fOK = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} catch (std::exception& e) {
|
|
strErrorMessages += std::string(e.what()) + std::string(";");
|
|
} catch (...) {
|
|
strErrorMessages += "Unknown exception;";
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
bool CProposalValidator::GetDataValue(const std::string& strKey, double& dValueRet)
|
|
{
|
|
bool fOK = false;
|
|
try {
|
|
const UniValue uValue = objJSON[strKey];
|
|
switch (uValue.getType()) {
|
|
case UniValue::VNUM:
|
|
dValueRet = uValue.get_real();
|
|
fOK = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} catch (std::exception& e) {
|
|
strErrorMessages += std::string(e.what()) + std::string(";");
|
|
} catch (...) {
|
|
strErrorMessages += "Unknown exception;";
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
/*
|
|
The purpose of this function is to replicate the behavior of the
|
|
Python urlparse function used by sentinel (urlparse.py). This function
|
|
should return false whenever urlparse raises an exception and true
|
|
otherwise.
|
|
*/
|
|
bool CProposalValidator::CheckURL(const std::string& strURLIn)
|
|
{
|
|
std::string strRest(strURLIn);
|
|
std::string::size_type nPos = strRest.find(':');
|
|
|
|
if (nPos != std::string::npos) {
|
|
//std::string strSchema = strRest.substr(0,nPos);
|
|
|
|
if (nPos < strRest.size()) {
|
|
strRest = strRest.substr(nPos + 1);
|
|
} else {
|
|
strRest = "";
|
|
}
|
|
}
|
|
|
|
// Process netloc
|
|
if ((strRest.size() > 2) && (strRest.substr(0, 2) == "//")) {
|
|
static const std::string strNetlocDelimiters = "/?#";
|
|
|
|
strRest = strRest.substr(2);
|
|
|
|
std::string::size_type nPos2 = strRest.find_first_of(strNetlocDelimiters);
|
|
|
|
std::string strNetloc = strRest.substr(0, nPos2);
|
|
|
|
if ((strNetloc.find('[') != std::string::npos) && (strNetloc.find(']') == std::string::npos)) {
|
|
return false;
|
|
}
|
|
|
|
if ((strNetloc.find(']') != std::string::npos) && (strNetloc.find('[') == std::string::npos)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|