diff --git a/src/Makefile.am b/src/Makefile.am index 4490fcd011c2..569097515a98 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,7 @@ BITCOIN_CORE_H = \ compat.h \ core.h \ mastercore.h \ + mastercore_parse_string.h \ mastercore_tx.h \ mastercore_dex.h \ mastercore_sp.h \ @@ -131,6 +132,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ core.cpp \ mastercore.cpp \ + mastercore_parse_string.cpp \ mastercore_tx.cpp \ mastercore_rpc.cpp \ mastercore_dex.cpp \ diff --git a/src/mastercore.cpp b/src/mastercore.cpp index 339c550fc5ed..0b463c148475 100644 --- a/src/mastercore.cpp +++ b/src/mastercore.cpp @@ -328,56 +328,6 @@ std::string FormatMP(unsigned int property, int64_t n, bool fSign) else return FormatIndivisibleMP(n); } -int64_t mastercore::strToInt64(std::string strAmount, bool divisible) -{ - int64_t Amount = 0; - - //check for a negative (minus sign) and invalidate if present - size_t negSignPos = strAmount.find("-"); - if (negSignPos!=std::string::npos) return 0; - - //convert the string into a usable int64 - if (divisible) - { - //check for existance of decimal point - size_t pos = strAmount.find("."); - if (pos==std::string::npos) - { //no decimal point but divisible so pad 8 zeros on right - strAmount+="00000000"; - } - else - { - size_t posSecond = strAmount.find(".", pos+1); //check for existence of second decimal point, if so invalidate amount - if (posSecond!=std::string::npos) return 0; - if ((strAmount.size()-pos)<9) - { //there are decimals either exact or not enough, pad as needed - string strRightOfDecimal = strAmount.substr(pos+1); - unsigned int zerosToPad = 8-strRightOfDecimal.size(); - if (zerosToPad>0) //do we need to pad? - { - for(unsigned int it = 0; it != zerosToPad; it++) - { - strAmount+="0"; - } - } - } - else - { //there are too many decimals, truncate after 8 - strAmount = strAmount.substr(0,pos+9); - } - } - strAmount.erase(std::remove(strAmount.begin(), strAmount.end(), '.'), strAmount.end()); - try { Amount = boost::lexical_cast(strAmount); } catch(const boost::bad_lexical_cast &e) { } - } - else - { - size_t pos = strAmount.find("."); - string newStrAmount = strAmount.substr(0,pos); - try { Amount = boost::lexical_cast(newStrAmount); } catch(const boost::bad_lexical_cast &e) { } - } -return Amount; -} - string const CMPSPInfo::watermarkKey("watermark"); CCriticalSection cs_tally; diff --git a/src/mastercore.h b/src/mastercore.h index 8315bc050516..7a072fd724f9 100644 --- a/src/mastercore.h +++ b/src/mastercore.h @@ -397,7 +397,6 @@ uint256 send_INTERNAL_1packet(const string &FromAddress, const string &ToAddress unsigned int TransactionType, int64_t additional, int *error_code = NULL); bool isTestEcosystemProperty(unsigned int property); -int64_t strToInt64(std::string strAmount, bool divisible); CMPTally *getTally(const string & address); diff --git a/src/mastercore_parse_string.cpp b/src/mastercore_parse_string.cpp new file mode 100644 index 000000000000..63471a8eec4e --- /dev/null +++ b/src/mastercore_parse_string.cpp @@ -0,0 +1,64 @@ +#include "mastercore_parse_string.h" + +#include +#include +#include + +#include + +namespace mastercore +{ +int64_t StrToInt64(const std::string& str, bool divisible) +{ + // copy original, so it remains unchanged + std::string strAmount (str); + int64_t nAmount = 0; + + // check for a negative (minus sign) and invalidate if present + size_t negSignPos = strAmount.find("-"); + if (negSignPos != std::string::npos) return 0; + + // convert the string into a usable int64 + if (divisible) { + // check for existance of decimal point + size_t pos = strAmount.find("."); + if (pos == std::string::npos) { + // no decimal point but divisible so pad 8 zeros on right + strAmount += "00000000"; + } else { + // check for existence of second decimal point, if so invalidate amount + size_t posSecond = strAmount.find(".", pos + 1); + if (posSecond != std::string::npos) return 0; + + if ((strAmount.size() - pos) < 9) { + // there are decimals either exact or not enough, pad as needed + std::string strRightOfDecimal = strAmount.substr(pos + 1); + unsigned int zerosToPad = 8 - strRightOfDecimal.size(); + + // do we need to pad? + if (zerosToPad > 0) + { + for (unsigned int it = 0; it != zerosToPad; it++) { + strAmount += "0"; + } + } + } else { + // there are too many decimals, truncate after 8 + strAmount = strAmount.substr(0, pos + 9); + } + } + strAmount.erase(std::remove(strAmount.begin(), strAmount.end(), '.'), strAmount.end()); + try { + nAmount = boost::lexical_cast(strAmount); + } catch (const boost::bad_lexical_cast &e) {} + } else { + size_t pos = strAmount.find("."); + std::string newStrAmount = strAmount.substr(0, pos); + try { + nAmount = boost::lexical_cast(newStrAmount); + } catch (const boost::bad_lexical_cast &e) {} + } + + return nAmount; +} +} // namespace mastercore diff --git a/src/mastercore_parse_string.h b/src/mastercore_parse_string.h new file mode 100644 index 000000000000..b66cea424625 --- /dev/null +++ b/src/mastercore_parse_string.h @@ -0,0 +1,20 @@ +#ifndef _MASTERCOIN_PARSE_STRING +#define _MASTERCOIN_PARSE_STRING + +#include +#include + +namespace mastercore +{ +// Converts strings to 64 bit wide interger. +// Divisible and indivisible amounts are accepted. +// 1 indivisible unit equals 0.00000001 divisible units. +// If input string is not a accepted number, 0 is returned. +// Divisible amounts are truncated after 8 decimal places. +// Characters after decimal mark are ignored for indivisible +// amounts. +// Any minus sign invalidates. +int64_t StrToInt64(const std::string& str, bool divisible); +} + +#endif // _MASTERCOIN_PARSE_STRRING diff --git a/src/mastercore_rpc.cpp b/src/mastercore_rpc.cpp index 771c46cddd76..f492797b91e2 100644 --- a/src/mastercore_rpc.cpp +++ b/src/mastercore_rpc.cpp @@ -35,6 +35,7 @@ using namespace json_spirit; using namespace mastercore; #include "mastercore_dex.h" +#include "mastercore_parse_string.h" #include "mastercore_tx.h" #include "mastercore_sp.h" #include "mastercore_errors.h" @@ -221,13 +222,13 @@ if (fHelp || params.size() < 4 || params.size() > 6) string strAmount = params[3].get_str(); int64_t Amount = 0, additional = 0; - Amount = strToInt64(strAmount, divisible); + Amount = StrToInt64(strAmount, divisible); if (0 >= Amount) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); std::string strAdditional = (params.size() > 5) ? (params[5].get_str()): "0"; - additional = strToInt64(strAdditional, true); + additional = StrToInt64(strAdditional, true); int n = params.size(); printf("#: %d, additional= %ld\n", n, additional); @@ -284,7 +285,7 @@ if (fHelp || params.size() < 3 || params.size() > 4) string strAmount = params[2].get_str(); int64_t Amount = 0; - Amount = strToInt64(strAmount, divisible); + Amount = StrToInt64(strAmount, divisible); if (0 >= Amount) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); @@ -328,7 +329,7 @@ if (fHelp || params.size() < 2 || params.size() > 5) int64_t referenceAmount = 0; if (params.size() > 4) - referenceAmount = strToInt64(params[4].get_str(), true); + referenceAmount = StrToInt64(params[4].get_str(), true); //some sanity checking of the data supplied? uint256 newTX; @@ -1092,11 +1093,11 @@ Value trade_MP(const Array& params, bool fHelp) { std::string strAmountSale = params[1].get_str(); int64_t Amount_Sale = 0; - Amount_Sale = strToInt64(strAmountSale, divisible_sale); + Amount_Sale = StrToInt64(strAmountSale, divisible_sale); std::string strAmountWant = params[3].get_str(); int64_t Amount_Want = 0; - Amount_Want = strToInt64(strAmountWant, divisible_want); + Amount_Want = StrToInt64(strAmountWant, divisible_want); if (0 >= Amount_Sale) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount (Sale)"); diff --git a/src/qt/sendmpdialog.cpp b/src/qt/sendmpdialog.cpp index 73650d7c70de..718a9e4906f3 100644 --- a/src/qt/sendmpdialog.cpp +++ b/src/qt/sendmpdialog.cpp @@ -56,6 +56,7 @@ using namespace leveldb; // end potentially overzealous using #include "mastercore_dex.h" +#include "mastercore_parse_string.h" #include "mastercore_tx.h" #include "mastercore_sp.h" @@ -292,7 +293,7 @@ void SendMPDialog::sendMPTransaction() } // use strToInt64 function to get the amount, using divisibility of the property - int64_t sendAmount = strToInt64(strAmount, divisible); + int64_t sendAmount = StrToInt64(strAmount, divisible); if (0>=sendAmount) { QMessageBox::critical( this, "Unable to send transaction", diff --git a/src/test/Makefile.am b/src/test/Makefile.am index e12f4904f14c..19b2321ad39a 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -47,6 +47,7 @@ test_bitcoin_SOURCES = \ getarg_tests.cpp \ key_tests.cpp \ main_tests.cpp \ + mastercore_strtoint64_tests.cpp \ miner_tests.cpp \ mruset_tests.cpp \ multisig_tests.cpp \ diff --git a/src/test/mastercore_strtoint64_tests.cpp b/src/test/mastercore_strtoint64_tests.cpp new file mode 100644 index 000000000000..412cea7e128c --- /dev/null +++ b/src/test/mastercore_strtoint64_tests.cpp @@ -0,0 +1,77 @@ +#include "mastercore_parse_string.h" + +#include + +#include + +using namespace mastercore; + +BOOST_AUTO_TEST_SUITE(mastercore_strtoint64_tests) + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_invidisible) +{ + // zero amount + BOOST_CHECK(StrToInt64("0", false) == 0); + // big num + BOOST_CHECK(StrToInt64("4000000000000000", false) == 4000000000000000); + // max int64 + BOOST_CHECK(StrToInt64("9223372036854775807", false) == 9223372036854775807); +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_invidisible_truncate) +{ + // ignore any char after decimal mark + BOOST_CHECK(StrToInt64("8.76543210123456878901", false) == 8); + BOOST_CHECK(StrToInt64("8.765432101.2345687890", false) == 8); + BOOST_CHECK(StrToInt64("2345.AbCdEhf71z1.23", false) == 2345); +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_invidisible_invalid) +{ + // invalid, number is negative + BOOST_CHECK(StrToInt64("-4", false) == 0); + // invalid, number is over max int64 + BOOST_CHECK(StrToInt64("9223372036854775808", false) == 0); + // invalid, minus sign in string + BOOST_CHECK(StrToInt64("2345.AbCdEFG71z88-1.23", false) == 0); +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_divisible) +{ + // range 0 to max int64 + BOOST_CHECK(StrToInt64("0.000", true) == 0); + BOOST_CHECK(StrToInt64("92233720368.54775807", true) == 9223372036854775807); + // check padding + BOOST_CHECK(StrToInt64("0.00000004", true) == 4); + BOOST_CHECK(StrToInt64("0.0000004", true) == 40); + BOOST_CHECK(StrToInt64("0.0004", true) == 40000); + BOOST_CHECK(StrToInt64("0.4", true) == 40000000); + BOOST_CHECK(StrToInt64("4.0", true) == 400000000); + // truncate after 8 digits + BOOST_CHECK(StrToInt64("40.00000000000099", true) == 4000000000); + BOOST_CHECK(StrToInt64("92233720368.54775807000", true) == 9223372036854775807); +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_divisible_truncate) +{ + // truncate after 8 digits + BOOST_CHECK(StrToInt64("40.00000000000099", true) == 4000000000); + BOOST_CHECK(StrToInt64("92233720368.54775807000", true) == 9223372036854775807); + BOOST_CHECK(StrToInt64("92233720368.54775807000", true) == 9223372036854775807); +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_divisible_invalid) +{ + // invalid, number is over max int64 + BOOST_CHECK(StrToInt64("92233720368.54775808", true) == 0); + // invalid, more than one decimal mark in string + BOOST_CHECK(StrToInt64("1234..12345678", true) == 0); + // invalid, alpha chars in string + BOOST_CHECK(StrToInt64("1234.12345A", true) == 0); + // invalid, number is negative + BOOST_CHECK(StrToInt64("-4.0", true) == 0); + // invalid, minus sign in string + BOOST_CHECK(StrToInt64("4.1234-5678", true) == 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/strtoint64.cpp b/src/tests/strtoint64.cpp deleted file mode 100644 index 300decc57194..000000000000 --- a/src/tests/strtoint64.cpp +++ /dev/null @@ -1,192 +0,0 @@ -//Tests for string to int64 conversion -//Build with g++ strtoint64.cpp -o main -//Execute with ./main and ensure all pass - -#include -#include -#include -#include -#include - -int64_t strToInt64(std::string strAmount, bool divisible) -{ - int64_t Amount = 0; - - //check for a negative (minus sign) and invalidate if present - size_t negSignPos = strAmount.find("-"); - if (negSignPos!=std::string::npos) return 0; - - //convert the string into a usable int64 - if (divisible) - { - //check for existance of decimal point - size_t pos = strAmount.find("."); - if (pos==std::string::npos) - { //no decimal point but divisible so pad 8 zeros on right - strAmount+="00000000"; - } - else - { - size_t posSecond = strAmount.find(".", pos+1); //check for existence of second decimal point, if so invalidate amount - if (posSecond!=std::string::npos) return 0; - if ((strAmount.size()-pos)<9) - { //there are decimals either exact or not enough, pad as needed - std::string strRightOfDecimal = strAmount.substr(pos+1); - unsigned int zerosToPad = 8-strRightOfDecimal.size(); - if (zerosToPad>0) //do we need to pad? - { - for(unsigned int it = 0; it != zerosToPad; it++) - { - strAmount+="0"; - } - } - } - else - { //there are too many decimals, truncate after 8 - strAmount = strAmount.substr(0,pos+9); - } - } - strAmount.erase(std::remove(strAmount.begin(), strAmount.end(), '.'), strAmount.end()); - try { Amount = boost::lexical_cast(strAmount); } catch(const boost::bad_lexical_cast &e) { } - } - else - { - size_t pos = strAmount.find("."); - std::string newStrAmount = strAmount.substr(0,pos); - try { Amount = boost::lexical_cast(newStrAmount); } catch(const boost::bad_lexical_cast &e) { } - } -return Amount; -} - -int main() -{ - int64_t amount = 0; - std::string strAmount; - int64_t expectedAmount = 0; - - printf("INDIVISIBLE TESTS:\n"); - - //4000000000000000 - indivisible - big num - strAmount = "4000000000000000"; - expectedAmount = 4000000000000000; - amount = strToInt64(strAmount, false); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //9223372036854775808 - indivisible - over max int64 - strAmount = "9223372036854775808"; - expectedAmount = 0; - amount = strToInt64(strAmount, false); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //9223372036854775807 - indivisible - max int64 - strAmount = "9223372036854775807"; - expectedAmount = 9223372036854775807; - amount = strToInt64(strAmount, false); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //-4 - indivisible - negative - strAmount = "-4"; - expectedAmount = 0; - amount = strToInt64(strAmount, false); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //0 indivisible - zero amount - strAmount = "0"; - expectedAmount = 0; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - printf("DIVISIBLE TESTS:\n"); - - //0.00000004 - divisible - check padding - strAmount = "0.00000004"; - expectedAmount = 4; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //0.0000004 - divisible - 7 digits check - strAmount = "0.0000004"; - expectedAmount = 40; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //0.0004 - divisible - check padding - strAmount = "0.0004"; - expectedAmount = 40000; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //0.4 - divisible - check padding - strAmount = "0.4"; - expectedAmount = 40000000; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //4.0 - divisible - check padding - strAmount = "4.0"; - expectedAmount = 400000000; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //40.00000000000099 - divisible - over 8 digits - strAmount = "40.00000000000099"; - expectedAmount = 4000000000; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //-4.0 - divisible - negative - strAmount = "-4.0"; - expectedAmount = 0; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //92233720368.54775807 - divisible - max int64 - strAmount = "92233720368.54775807"; - expectedAmount = 9223372036854775807; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //92233720368.54775808 - divisible - over max int64 - strAmount = "92233720368.54775808"; - expectedAmount = 0; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //1234..12345678 - divisible - more than one decimal in string - strAmount = "1234..12345678"; - expectedAmount = 0; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //1234.12345A - divisible - alpha chars in string - strAmount = "1234.12345A"; - expectedAmount = 0; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - - //0 divisible - zero amount - strAmount = "0.000"; - expectedAmount = 0; - amount = strToInt64(strAmount, true); - printf("Amount detected: %lu - ", amount); - if (amount == expectedAmount) { printf("Pass converting from %s\n",strAmount.c_str()); } else { printf("Fail converting from %s\n",strAmount.c_str()); } - -} - -