diff --git a/src/Makefile.am b/src/Makefile.am index 4490fcd011c2..9c2fd96470f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,10 +39,12 @@ BITCOIN_CORE_H = \ compat.h \ core.h \ mastercore.h \ - mastercore_tx.h \ + mastercore_convert.h \ mastercore_dex.h \ - mastercore_sp.h \ mastercore_errors.h \ + mastercore_format.h \ + mastercore_sp.h \ + mastercore_tx.h \ crypter.h \ db.h \ hash.h \ @@ -131,10 +133,12 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ core.cpp \ mastercore.cpp \ - mastercore_tx.cpp \ - mastercore_rpc.cpp \ + mastercore_convert.cpp \ mastercore_dex.cpp \ + mastercore_format.cpp \ + mastercore_rpc.cpp \ mastercore_sp.cpp \ + mastercore_tx.cpp \ hash.cpp \ key.cpp \ netbase.cpp \ diff --git a/src/mastercore.cpp b/src/mastercore.cpp index 847ab59356f6..32cfb812249a 100644 --- a/src/mastercore.cpp +++ b/src/mastercore.cpp @@ -76,7 +76,9 @@ using namespace mastercore; #include "mastercore_dex.h" #include "mastercore_tx.h" #include "mastercore_sp.h" +#include "mastercore_convert.h" #include "mastercore_errors.h" +#include "mastercore_format.h" // part of 'breakout' feature static const int nBlockTop = 0; @@ -287,91 +289,11 @@ void swapByteOrder64(uint64_t& ull) (ull << 56); } -uint64_t rounduint64(double d) -{ - return (uint64_t)(abs(0.5 + d)); -} - bool isNonMainNet() { return (TestNet() || RegTest()); } -// mostly taken from Bitcoin's FormatMoney() -string FormatDivisibleMP(int64_t n, bool fSign) -{ -// Note: not using straight sprintf here because we do NOT want -// localized number formatting. -int64_t n_abs = (n > 0 ? n : -n); -int64_t quotient = n_abs/COIN; -int64_t remainder = n_abs%COIN; -string str = strprintf("%d.%08d", quotient, remainder); - - if (!fSign) return str; - - if (n < 0) - str.insert((unsigned int)0, 1, '-'); - else - str.insert((unsigned int)0, 1, '+'); - return str; -} - -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; -} - -std::string mastercore::FormatIndivisibleMP(int64_t n) -{ - string str = strprintf("%ld", n); - return str; -} - string const CMPSPInfo::watermarkKey("watermark"); CCriticalSection cs_tally; @@ -800,7 +722,7 @@ const double years = seconds_passed/seconds_in_one_year; const double part_available = 1 - pow(0.5, years); const double available_reward=all_reward * part_available; - devmsc = rounduint64(available_reward); + devmsc = RoundToUInt64(available_reward); exodus_delta = devmsc - exodus_prev; if (msc_debug_exo) fprintf(mp_fp, "devmsc=%lu, exodus_prev=%lu, exodus_delta=%ld\n", devmsc, exodus_prev, exodus_delta); @@ -3758,7 +3680,7 @@ int rc = PKT_ERROR_STO -1000; owns, address.c_str(), percentage, piece, should_receive, will_really_receive, sent_so_far); // record the detailed info as needed - if (fhandle) fprintf(fhandle, "%s = %s\n", address.c_str(), bDivisible ? FormatDivisibleMP(will_really_receive).c_str() : FormatIndivisibleMP(will_really_receive).c_str()); + if (fhandle) fprintf(fhandle, "%s = %s\n", address.c_str(), FormatTokenAmount(will_really_receive, bDivisible).c_str()); if (!update_tally_map(sender, currency, - will_really_receive, MONEY)) { diff --git a/src/mastercore.h b/src/mastercore.h index ca5b001f8836..70f037c0e314 100644 --- a/src/mastercore.h +++ b/src/mastercore.h @@ -6,6 +6,8 @@ #ifndef _MASTERCOIN #define _MASTERCOIN 1 +#include "mastercore_format.h" + #include "netbase.h" #include "protocol.h" @@ -130,7 +132,6 @@ enum FILETYPES { #define MASTERCOIN_CURRENCY_TMSC 2 // forward declarations -string FormatDivisibleMP(int64_t n, bool fSign = false); uint256 send_MP(const string &FromAddress, const string &ToAddress, const string &RedeemAddress, unsigned int CurrencyID, uint64_t Amount); int64_t feeCheck(const string &address); @@ -237,7 +238,7 @@ typedef struct if (bDivisible) { printf("%22s [SO_RESERVE= %22s , ACCEPT_RESERVE= %22s ] %22s\n", - FormatDivisibleMP(money, true).c_str(), FormatDivisibleMP(so_r, true).c_str(), FormatDivisibleMP(a_r, true).c_str(), FormatDivisibleMP(pending, true).c_str()); + FormatDivisibleAmount(money, true).c_str(), FormatDivisibleAmount(so_r, true).c_str(), FormatDivisibleAmount(a_r, true).c_str(), FormatDivisibleAmount(pending, true).c_str()); } else { @@ -362,8 +363,6 @@ int mastercore_handler_block_end(int nBlockNow, CBlockIndex const * pBlockIndex, int mastercore_handler_tx(const CTransaction &tx, int nBlock, unsigned int idx, CBlockIndex const *pBlockIndex ); int mastercore_save_state( CBlockIndex const *pBlockIndex ); -uint64_t rounduint64(double d); - bool isBigEndian(void); void swapByteOrder16(unsigned short& us); @@ -386,7 +385,6 @@ string getPropertyName(unsigned int propertyId); bool isCrowdsaleActive(unsigned int propertyId); bool isCrowdsalePurchase(uint256 txid, string address, int64_t *propertyId = NULL, int64_t *userTokens = NULL, int64_t *issuerTokens = NULL); bool isMPinBlockRange(int starting_block, int ending_block, bool bDeleteFound); -std::string FormatIndivisibleMP(int64_t n); int ClassB_send(const string &senderAddress, const string &receiverAddress, const string &redemptionAddress, const vector &data, uint256 & txid, int64_t additional = 0); @@ -394,7 +392,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_convert.cpp b/src/mastercore_convert.cpp new file mode 100644 index 000000000000..c2473b16fa52 --- /dev/null +++ b/src/mastercore_convert.cpp @@ -0,0 +1,65 @@ +#include "mastercore_convert.h" + +#include + +#include +#include +#include + +uint64_t RoundToUInt64(long double d) { + return static_cast(labs(d + 0.5l)); +} + +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; +} diff --git a/src/mastercore_convert.h b/src/mastercore_convert.h new file mode 100644 index 000000000000..592edf65f1be --- /dev/null +++ b/src/mastercore_convert.h @@ -0,0 +1,20 @@ +#ifndef _MASTERCOIN_CONVERT +#define _MASTERCOIN_CONVERT + +#include +#include + +// Converts numbers into 64 bit wide integer and rounds +// up. +uint64_t RoundToUInt64(long double d); + +// Converts a string into an integer. Divisible as well as +// indivisible amounts are accepted. Invalid inputs result +// in 0. Any "-" invalidates the string. +// 1 indivisible unit equals 0.00000001 divisible units. +// Divisible amounts are truncated after the 8 digit, right +// behind the first and only decimal point ".". +// Indivisible amounts are truncated after a decimal point. +int64_t StrToInt64(const std::string& str, bool divisible); + +#endif // _MASTERCOIN_CONVERT diff --git a/src/mastercore_dex.cpp b/src/mastercore_dex.cpp index 65f274afd8b7..def651fc2bef 100644 --- a/src/mastercore_dex.cpp +++ b/src/mastercore_dex.cpp @@ -51,6 +51,8 @@ using namespace mastercore; #include "mastercore_dex.h" #include "mastercore_tx.h" +#include "mastercore_convert.h" +#include "mastercore_format.h" extern int msc_debug_dex, msc_debug_metadex, msc_debug_metadex2; @@ -274,7 +276,7 @@ std::string CMPMetaDEx::ToString() const { return strprintf("%34s in %d/%03u, txid: %s, trade #%u %s for #%u %s; unit_price = %lu.%010lu, inverse= %lu.%010lu", addr.c_str(), block, idx, txid.ToString().substr(0,10).c_str(), - currency, FormatDivisibleMP(amount_original), desired_currency, FormatDivisibleMP(desired_amount_original), + currency, FormatDivisibleAmount(amount_original), desired_currency, FormatDivisibleAmount(desired_amount_original), price_int, price_frac, inverse_int, inverse_frac); } @@ -339,7 +341,7 @@ int rc = DEX_ERROR_SELLOFFER; // AND we must also re-adjust the BTC desired in this case... BTC = amount_desired * balanceReallyAvailable; BTC /= (double)nValue; - amount_desired = rounduint64(BTC); + amount_desired = RoundToUInt64(BTC); nValue = balanceReallyAvailable; @@ -561,7 +563,7 @@ p_accept = DEx_getAccept(seller, curr, buyer); double perc_X = (double)BTC_paid/BTC_desired_original; double Purchased = offer_amount_original * perc_X; - uint64_t units_purchased = rounduint64(Purchased); + uint64_t units_purchased = RoundToUInt64(Purchased); const uint64_t nActualAmount = p_accept->getAcceptAmountRemaining(); // actual amount desired, in the Accept diff --git a/src/mastercore_format.cpp b/src/mastercore_format.cpp new file mode 100644 index 000000000000..378894d2560b --- /dev/null +++ b/src/mastercore_format.cpp @@ -0,0 +1,55 @@ +#include "mastercore_format.h" + +// TODO: find a way to use strprintf/tfm::format directly +// It currently relies on util.h and tinyformat.h, but has heavy dependencies +#include "util.h" + +#include +#include + +std::string FormatTokenAmount(int64_t n) +{ + // Default token amounts are formatted as indivisible + // token which aligns well with an integer input + return FormatIndivisibleAmount(n); +} + +std::string FormatTokenAmount(int64_t n, bool divisible) +{ + if (divisible) + return FormatDivisibleAmount(n); + + return FormatIndivisibleAmount(n); +} + +std::string FormatIndivisibleAmount(int64_t n) +{ + return tfm::format("%d", n); +} + +std::string FormatDivisibleAmount(int64_t n) +{ + // Prepend sign only for negative numbers + bool is_negative = (n < 0); + return FormatDivisibleAmount(n, is_negative); +} + +std::string FormatDivisibleAmount(int64_t n, bool sign) +{ + // Note: not using straight sprintf here because we do NOT want + // localized number formatting. + int64_t n_abs = (n > 0 ? n : -n); + int64_t quotient = n_abs / COIN; + int64_t remainder = n_abs % COIN; + std::string str = tfm::format("%d.%08d", quotient, remainder); + + if (!sign) + return str; + + if (n < 0) + str.insert((unsigned int) 0, 1, '-'); + else + str.insert((unsigned int) 0, 1, '+'); + + return str; +} diff --git a/src/mastercore_format.h b/src/mastercore_format.h new file mode 100644 index 000000000000..f9c3737714f2 --- /dev/null +++ b/src/mastercore_format.h @@ -0,0 +1,23 @@ +#ifndef _MASTERCOIN_FORMAT +#define _MASTERCOIN_FORMAT + +#include +#include + +// Formats a value as token amount and prepends a minus sign, +// if the value is negative. Divisible amounts have 8 digits. +// Per default n is formatted as indivisible amount. +std::string FormatTokenAmount(int64_t n); +std::string FormatTokenAmount(int64_t n, bool divisible); + +// Formats a value as indivisible token amount with leading +// minus sign, if n is negative. +std::string FormatIndivisibleAmount(int64_t n); + +// Formats a value as divisible token amount with 8 digits. +// Per default a minus sign is prepended, if n is negative. +// A positive or negative sign can be enforced. +std::string FormatDivisibleAmount(int64_t n); +std::string FormatDivisibleAmount(int64_t n, bool sign); + +#endif // _MASTERCOIN_FORMAT diff --git a/src/mastercore_rpc.cpp b/src/mastercore_rpc.cpp index 4470fcf08630..024cdfa4b357 100644 --- a/src/mastercore_rpc.cpp +++ b/src/mastercore_rpc.cpp @@ -37,7 +37,9 @@ using namespace mastercore; #include "mastercore_dex.h" #include "mastercore_tx.h" #include "mastercore_sp.h" +#include "mastercore_convert.h" #include "mastercore_errors.h" +#include "mastercore_format.h" // display the tally map & the offer/accept list(s) Value mscrpc(const Array& params, bool fHelp) @@ -81,7 +83,7 @@ int extra2 = 0, extra3 = 0; total += (my_it->second).print(extra2, bDivisible); } - printf("total for property %d = %X is %s\n", extra2, extra2, FormatDivisibleMP(total).c_str()); + printf("total for property %d = %X is %s\n", extra2, extra2, FormatDivisibleAmount(total).c_str()); } break; @@ -155,37 +157,29 @@ Value getbalance_MP(const Array& params, bool fHelp) "\nExamples:\n" ">mastercored getbalance_MP 1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P 1\n" ); + std::string address = params[0].get_str(); int64_t tmpPropertyId = params[1].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); CMPSPInfo::Entry sp; if (false == _my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); } - bool divisible = false; - divisible=sp.isDivisible(); - - Object balObj; - int64_t tmpBalAvailable = getUserAvailableMPbalance(address, propertyId); int64_t tmpBalReservedSell = getMPbalance(address, propertyId, SELLOFFER_RESERVE); int64_t tmpBalReservedAccept = 0; - if (propertyId<3) tmpBalReservedAccept = getMPbalance(address, propertyId, ACCEPT_RESERVE); + if (propertyId < 3) + tmpBalReservedAccept = getMPbalance(address, propertyId, ACCEPT_RESERVE); - if (divisible) - { - balObj.push_back(Pair("balance", FormatDivisibleMP(tmpBalAvailable))); - balObj.push_back(Pair("reserved", FormatDivisibleMP(tmpBalReservedSell+tmpBalReservedAccept))); - } - else - { - balObj.push_back(Pair("balance", FormatIndivisibleMP(tmpBalAvailable))); - balObj.push_back(Pair("reserved", FormatIndivisibleMP(tmpBalReservedSell+tmpBalReservedAccept))); - } + bool divisible = sp.isDivisible(); + + Object balObj; + balObj.push_back(Pair("balance", FormatTokenAmount(tmpBalAvailable, divisible))); + balObj.push_back(Pair("reserved", FormatTokenAmount(tmpBalReservedSell + tmpBalReservedAccept, divisible))); return balObj; } @@ -216,7 +210,7 @@ if (fHelp || params.size() < 4 || params.size() > 6) int64_t tmpPropertyId = params[2].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); CMPSPInfo::Entry sp; @@ -229,19 +223,19 @@ 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"); + 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); if ((0.01 * COIN) < additional) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid referenceamount"); + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid referenceamount"); //some sanity checking of the data supplied? int code = 0; @@ -276,7 +270,7 @@ if (fHelp || params.size() < 3 || params.size() > 4) int64_t tmpPropertyId = params[1].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); @@ -292,10 +286,10 @@ 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"); + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); // printf("%s() %40.25lf, %lu, line %d, file: %s\n", __FUNCTION__, tmpAmount, Amount, __LINE__, __FILE__); @@ -336,7 +330,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; @@ -352,7 +346,7 @@ if (fHelp || params.size() < 2 || params.size() > 5) Value getallbalancesforid_MP(const Array& params, bool fHelp) { - if (fHelp || params.size() != 1) + if (fHelp || params.size() != 1) throw runtime_error( "getallbalancesforid_MP propertyid\n" "\nGet a list of balances for a given currency or property identifier.\n" @@ -372,16 +366,15 @@ Value getallbalancesforid_MP(const Array& params, bool fHelp) int64_t tmpPropertyId = params[0].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); CMPSPInfo::Entry sp; if (false == _my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); } - bool divisible=false; - divisible=sp.isDivisible(); + bool divisible = sp.isDivisible(); Array response; @@ -393,32 +386,25 @@ Value getallbalancesforid_MP(const Array& params, bool fHelp) (my_it->second).init(); while (0 != (id = (my_it->second).next())) { - if(id==propertyId) { includeAddress=true; break; } + if(id==propertyId) { includeAddress=true; break; } } if (!includeAddress) continue; //ignore this address, has never transacted in this propertyId - Object addressbal; - int64_t tmpBalAvailable = getUserAvailableMPbalance(address, propertyId); int64_t tmpBalReservedSell = getMPbalance(address, propertyId, SELLOFFER_RESERVE); int64_t tmpBalReservedAccept = 0; - if (propertyId<3) tmpBalReservedAccept = getMPbalance(address, propertyId, ACCEPT_RESERVE); + if (propertyId < 3) + tmpBalReservedAccept = getMPbalance(address, propertyId, ACCEPT_RESERVE); + Object addressbal; addressbal.push_back(Pair("address", address)); - if(divisible) - { - addressbal.push_back(Pair("balance", FormatDivisibleMP(tmpBalAvailable))); - addressbal.push_back(Pair("reserved", FormatDivisibleMP(tmpBalReservedSell+tmpBalReservedAccept))); - } - else - { - addressbal.push_back(Pair("balance", FormatIndivisibleMP(tmpBalAvailable))); - addressbal.push_back(Pair("reserved", FormatIndivisibleMP(tmpBalReservedSell+tmpBalReservedAccept))); - } + addressbal.push_back(Pair("balance", FormatTokenAmount(tmpBalAvailable, divisible))); + addressbal.push_back(Pair("reserved", FormatTokenAmount(tmpBalReservedSell + tmpBalReservedAccept, divisible))); + response.push_back(addressbal); } -return response; + return response; } Value getallbalancesforaddress_MP(const Array& params, bool fHelp) @@ -445,47 +431,38 @@ Value getallbalancesforaddress_MP(const Array& params, bool fHelp) address = params[0].get_str(); if (address.empty()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address"); Array response; CMPTally *addressTally=getTally(address); if (NULL == addressTally) // addressTally object does not exist - throw JSONRPCError(RPC_INVALID_PARAMETER, "Address not found"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Address not found"); addressTally->init(); uint64_t propertyId; // avoid issues with json spirit at uint32 while (0 != (propertyId = addressTally->next())) { - bool divisible=false; - CMPSPInfo::Entry sp; - if (_my_sps->getSP(propertyId, sp)) { - divisible = sp.isDivisible(); - } - - Object propertyBal; - - propertyBal.push_back(Pair("propertyid", propertyId)); - - int64_t tmpBalAvailable = getUserAvailableMPbalance(address, propertyId); - int64_t tmpBalReservedSell = getMPbalance(address, propertyId, SELLOFFER_RESERVE); - int64_t tmpBalReservedAccept = 0; - if (propertyId<3) tmpBalReservedAccept = getMPbalance(address, propertyId, ACCEPT_RESERVE); - - if (divisible) - { - propertyBal.push_back(Pair("balance", FormatDivisibleMP(tmpBalAvailable))); - propertyBal.push_back(Pair("reserved", FormatDivisibleMP(tmpBalReservedSell+tmpBalReservedAccept))); - } - else - { - propertyBal.push_back(Pair("balance", FormatIndivisibleMP(tmpBalAvailable))); - propertyBal.push_back(Pair("reserved", FormatIndivisibleMP(tmpBalReservedSell+tmpBalReservedAccept))); - } + bool divisible = false; + CMPSPInfo::Entry sp; + if (_my_sps->getSP(propertyId, sp)) { + divisible = sp.isDivisible(); + } - response.push_back(propertyBal); + int64_t tmpBalAvailable = getUserAvailableMPbalance(address, propertyId); + int64_t tmpBalReservedSell = getMPbalance(address, propertyId, SELLOFFER_RESERVE); + int64_t tmpBalReservedAccept = 0; + if (propertyId < 3) + tmpBalReservedAccept = getMPbalance(address, propertyId, ACCEPT_RESERVE); + + Object propertyBal; + propertyBal.push_back(Pair("propertyid", propertyId)); + propertyBal.push_back(Pair("balance", FormatTokenAmount(tmpBalAvailable, divisible))); + propertyBal.push_back(Pair("reserved", FormatTokenAmount(tmpBalReservedSell + tmpBalReservedAccept, divisible))); + + response.push_back(propertyBal); } return response; @@ -519,12 +496,12 @@ Value getproperty_MP(const Array& params, bool fHelp) int64_t tmpPropertyId = params[0].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); CMPSPInfo::Entry sp; if (false == _my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); } Object response; @@ -551,14 +528,7 @@ Value getproperty_MP(const Array& params, bool fHelp) response.push_back(Pair("issuer", issuer)); response.push_back(Pair("creationtxid", creationTXID.GetHex())); response.push_back(Pair("fixedissuance", fixedIssuance)); - if (divisible) - { - response.push_back(Pair("totaltokens", FormatDivisibleMP(totalTokens))); - } - else - { - response.push_back(Pair("totaltokens", FormatIndivisibleMP(totalTokens))); - } + response.push_back(Pair("totaltokens", FormatDivisibleAmount(totalTokens, divisible))); return response; } @@ -676,12 +646,12 @@ Value getcrowdsale_MP(const Array& params, bool fHelp) int64_t tmpPropertyId = params[0].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); CMPSPInfo::Entry sp; if (false == _my_sps->getSP(propertyId, sp)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Property ID does not exist"); } bool showVerbose = false; @@ -690,7 +660,7 @@ Value getcrowdsale_MP(const Array& params, bool fHelp) bool fixedIssuance = sp.fixed; bool manualIssuance = sp.manual; if (fixedIssuance || manualIssuance) // property was not a variable issuance - throw JSONRPCError(RPC_INVALID_PARAMETER, "Property was not created with a crowdsale"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Property was not created with a crowdsale"); uint256 creationHash = sp.txid; @@ -753,7 +723,7 @@ Value getcrowdsale_MP(const Array& params, bool fHelp) bool divisibleDesired = false; CMPSPInfo::Entry spDesired; if (false == _my_sps->getSP(propertyId, spDesired)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Desired property ID does not exist"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Desired property ID does not exist"); } divisibleDesired = spDesired.isDivisible(); divisibleDesired = isPropertyDivisible(propertyIdDesired); @@ -770,31 +740,11 @@ Value getcrowdsale_MP(const Array& params, bool fHelp) int64_t amountSent = it->second.at(0); amountRaised += amountSent; - participanttx.push_back(Pair("txid", txid)); //.GetHex()).c_str(); - if (divisibleDesired) - { - participanttx.push_back(Pair("amountsent", FormatDivisibleMP(amountSent))); - } - else - { - participanttx.push_back(Pair("amountsent", FormatIndivisibleMP(amountSent))); - } - if (divisible) - { - participanttx.push_back(Pair("participanttokens", FormatDivisibleMP(userTokens))); - } - else - { - participanttx.push_back(Pair("participanttokens", FormatIndivisibleMP(userTokens))); - } - if (divisible) - { - participanttx.push_back(Pair("issuertokens", FormatDivisibleMP(issuerTokens))); - } - else - { - participanttx.push_back(Pair("issuertokens", FormatIndivisibleMP(issuerTokens))); - } + participanttx.push_back(Pair("txid", txid)); + participanttx.push_back(Pair("amountsent", FormatTokenAmount(amountSent, divisible))); + participanttx.push_back(Pair("participanttokens", FormatTokenAmount(userTokens, divisible))); + participanttx.push_back(Pair("issuertokens", FormatTokenAmount(issuerTokens, divisible))); + participanttxs.push_back(participanttx); } @@ -802,37 +752,15 @@ Value getcrowdsale_MP(const Array& params, bool fHelp) response.push_back(Pair("active", active)); response.push_back(Pair("issuer", issuer)); response.push_back(Pair("propertyiddesired", propertyIdDesired)); - if (divisible) - { - response.push_back(Pair("tokensperunit", FormatDivisibleMP(tokensPerUnit))); - } - else - { - response.push_back(Pair("tokensperunit", FormatIndivisibleMP(tokensPerUnit))); - } + response.push_back(Pair("tokensperunit", FormatTokenAmount(tokensPerUnit, divisible))); response.push_back(Pair("earlybonus", earlyBonus)); response.push_back(Pair("percenttoissuer", percentToIssuer)); response.push_back(Pair("starttime", startTime)); response.push_back(Pair("deadline", deadline)); + response.push_back(Pair("amountraised", FormatTokenAmount(amountRaised, divisibleDesired))); + response.push_back(Pair("tokensissued", FormatTokenAmount(tokensIssued, divisible))); + response.push_back(Pair("addedissuertokens", FormatTokenAmount(missedTokens, divisible))); - if (divisibleDesired) - { - response.push_back(Pair("amountraised", FormatDivisibleMP(amountRaised))); - } - else - { - response.push_back(Pair("amountraised", FormatIndivisibleMP(amountRaised))); - } - if (divisible) - { - response.push_back(Pair("tokensissued", FormatDivisibleMP(tokensIssued))); - response.push_back(Pair("addedissuertokens", FormatDivisibleMP(missedTokens))); - } - else - { - response.push_back(Pair("tokensissued", FormatIndivisibleMP(tokensIssued))); - response.push_back(Pair("addedissuertokens", FormatIndivisibleMP(missedTokens))); - } if (!active) response.push_back(Pair("closedearly", closeEarly)); if (!active) response.push_back(Pair("maxtokens", maxTokens)); if (closeEarly) response.push_back(Pair("endedtime", timeClosed)); @@ -907,14 +835,7 @@ Value getactivecrowdsales_MP(const Array& params, bool fHelp) responseObj.push_back(Pair("name", propertyName)); responseObj.push_back(Pair("issuer", issuer)); responseObj.push_back(Pair("propertyiddesired", propertyIdDesired)); - if (divisible) - { - responseObj.push_back(Pair("tokensperunit", FormatDivisibleMP(tokensPerUnit))); - } - else - { - responseObj.push_back(Pair("tokensperunit", FormatIndivisibleMP(tokensPerUnit))); - } + responseObj.push_back(Pair("tokensperunit", FormatTokenAmount(tokensPerUnit, divisible))); responseObj.push_back(Pair("earlybonus", earlyBonus)); responseObj.push_back(Pair("percenttoissuer", percentToIssuer)); responseObj.push_back(Pair("starttime", startTime)); @@ -961,7 +882,7 @@ Value getgrants_MP(const Array& params, bool fHelp) int64_t tmpPropertyId = params[0].get_int64(); if ((1 > tmpPropertyId) || (4294967295 < tmpPropertyId)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID"); unsigned int propertyId = int(tmpPropertyId); CMPSPInfo::Entry sp; @@ -995,22 +916,14 @@ Value getgrants_MP(const Array& params, bool fHelp) if (grantedTokens > 0){ Object granttx; granttx.push_back(Pair("txid", txid)); - if (sp.isDivisible()) { - granttx.push_back(Pair("grant", FormatDivisibleMP(grantedTokens))); - } else { - granttx.push_back(Pair("grant", FormatIndivisibleMP(grantedTokens))); - } + granttx.push_back(Pair("grant", FormatTokenAmount(grantedTokens, sp.isDivisible()))); issuancetxs.push_back(granttx); } if (revokedTokens > 0){ Object revoketx; revoketx.push_back(Pair("txid", txid)); - if (sp.isDivisible()) { - revoketx.push_back(Pair("revoke", FormatDivisibleMP(revokedTokens))); - } else { - revoketx.push_back(Pair("revoke", FormatIndivisibleMP(revokedTokens))); - } + revoketx.push_back(Pair("revoke", FormatTokenAmount(revokedTokens, sp.isDivisible()))); issuancetxs.push_back(revoketx); } } @@ -1018,11 +931,7 @@ Value getgrants_MP(const Array& params, bool fHelp) response.push_back(Pair("name", propertyName)); response.push_back(Pair("issuer", issuer)); response.push_back(Pair("creationtxid", creationHash.GetHex())); - if (sp.isDivisible()) { - response.push_back(Pair("totaltokens", FormatDivisibleMP(totalTokens))); - } else { - response.push_back(Pair("totaltokens", FormatIndivisibleMP(totalTokens))); - } + response.push_back(Pair("totaltokens", FormatTokenAmount(totalTokens, sp.isDivisible()))); response.push_back(Pair("issuances", issuancetxs)); return response; } @@ -1059,12 +968,12 @@ Value trade_MP(const Array& params, bool fHelp) { int64_t tmpPropIdSale = params[2].get_int64(); if ((1 > tmpPropIdSale) || (4294967295 < tmpPropIdSale)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID (Sale)"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID (Sale)"); unsigned int propertyIdSale = int(tmpPropIdSale); int64_t tmpPropIdWant = params[4].get_int64(); if ((1 > tmpPropIdWant) || (4294967295 < tmpPropIdWant)) // not safe to do conversion - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID (Want)"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid property ID (Want)"); unsigned int propertyIdWant = int(tmpPropIdWant); CMPSPInfo::Entry sp_sale; @@ -1090,14 +999,14 @@ 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)"); + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount (Sale)"); if (0 >= Amount_Want) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount (Want)"); @@ -1194,8 +1103,8 @@ Value getorderbook_MP(const Array& params, bool fHelp) { metadex_obj.push_back(Pair("unit_price", strprintf("%lu.%.8s", price[0], boost::lexical_cast(price[1]) ).c_str() ) ); metadex_obj.push_back(Pair("inverse_unit_price", strprintf("%lu.%.8s", invprice[0], boost::lexical_cast(invprice[1]) ).c_str() ) ); //active? - metadex_obj.push_back(Pair("amount_original", FormatDivisibleMP((it->second).getAmtOrig()))); - metadex_obj.push_back(Pair("amount_desired", FormatDivisibleMP((it->second).getAmtDes()))); + metadex_obj.push_back(Pair("amount_original", FormatDivisibleAmount((it->second).getAmtOrig()))); + metadex_obj.push_back(Pair("amount_desired", FormatDivisibleAmount((it->second).getAmtDes()))); metadex_obj.push_back(Pair("action", (uint64_t) (it->second).getAction())); metadex_obj.push_back(Pair("block", (it->second).getBlock())); response.push_back(metadex_obj); @@ -1324,22 +1233,22 @@ Value getactivedexsells_MP(const Array& params, bool fHelp) //unit price & updated bitcoin desired calcs double unitPriceFloat = 0; if ((sellOfferAmount>0) && (sellBitcoinDesired > 0)) unitPriceFloat = (double)sellBitcoinDesired/(double)sellOfferAmount; //divide by zero protection - uint64_t unitPrice = rounduint64(unitPriceFloat * COIN); - uint64_t bitcoinDesired = rounduint64(amountAvailable*unitPriceFloat); + uint64_t unitPrice = RoundToUInt64(unitPriceFloat * COIN); + uint64_t bitcoinDesired = RoundToUInt64(amountAvailable*unitPriceFloat); Object responseObj; responseObj.push_back(Pair("txid", txid)); responseObj.push_back(Pair("propertyid", propertyId)); responseObj.push_back(Pair("seller", seller)); - responseObj.push_back(Pair("amountavailable", FormatDivisibleMP(amountAvailable))); - responseObj.push_back(Pair("bitcoindesired", FormatDivisibleMP(bitcoinDesired))); - responseObj.push_back(Pair("unitprice", FormatDivisibleMP(unitPrice))); + responseObj.push_back(Pair("amountavailable", FormatDivisibleAmount(amountAvailable))); + responseObj.push_back(Pair("bitcoindesired", FormatDivisibleAmount(bitcoinDesired))); + responseObj.push_back(Pair("unitprice", FormatDivisibleAmount(unitPrice))); responseObj.push_back(Pair("timelimit", timeLimit)); - responseObj.push_back(Pair("minimumfee", FormatDivisibleMP(minFee))); + responseObj.push_back(Pair("minimumfee", FormatDivisibleAmount(minFee))); // display info about accepts related to sell - responseObj.push_back(Pair("amountaccepted", FormatDivisibleMP(amountAccepted))); + responseObj.push_back(Pair("amountaccepted", FormatDivisibleAmount(amountAccepted))); Array acceptsMatched; for(AcceptMap::iterator ait = my_accepts.begin(); ait != my_accepts.end(); ++ait) { @@ -1357,7 +1266,7 @@ Value getactivedexsells_MP(const Array& params, bool fHelp) uint64_t acceptAmount = accept.getAcceptAmountRemaining(); matchedAccept.push_back(Pair("buyer", buyer)); matchedAccept.push_back(Pair("block", acceptBlock)); - matchedAccept.push_back(Pair("amount", FormatDivisibleMP(acceptAmount))); + matchedAccept.push_back(Pair("amount", FormatDivisibleAmount(acceptAmount))); acceptsMatched.push_back(matchedAccept); } } @@ -1392,7 +1301,7 @@ Value listblocktransactions_MP(const Array& params, bool fHelp) // firstly let's get the block height given in the param int blockHeight = params[0].get_int(); if (blockHeight < 0 || blockHeight > GetHeight()) - throw runtime_error("Cannot display MP transactions for a non-existent block."); + throw runtime_error("Cannot display MP transactions for a non-existent block."); // next let's obtain the block for this height CBlockIndex* mpBlockIndex = chainActive[blockHeight]; @@ -1400,7 +1309,7 @@ Value listblocktransactions_MP(const Array& params, bool fHelp) // now let's read this block in from disk so we can loop its transactions if(!ReadBlockFromDisk(mpBlock, mpBlockIndex)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal Error: Failed to read block from disk"); + throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal Error: Failed to read block from disk"); // create an array to hold our response Array response; @@ -1435,10 +1344,9 @@ static int populateRPCTransactionObject(uint256 txid, Object *txobj, string filt uint256 wtxid = txid; bool bIsMine; bool isMPTx = false; - int nFee = 0; + uint64_t nFee = 0; string MPTxType; - unsigned int MPTxTypeInt; - string selectedAddress; + unsigned int MPTxTypeInt = 65535; // "invalid"; string senderAddress; string refAddress; bool valid; @@ -1497,7 +1405,12 @@ static int populateRPCTransactionObject(uint256 txid, Object *txobj, string filt uint64_t tmpVout; uint64_t tmpNValue; uint64_t tmpPropertyId; - p_txlistdb->getPurchaseDetails(wtxid,1,&tmpBuyer,&tmpSeller,&tmpVout,&tmpPropertyId,&tmpNValue); + if (!p_txlistdb->getPurchaseDetails(wtxid,1,&tmpBuyer,&tmpSeller,&tmpVout,&tmpPropertyId,&tmpNValue)) + { // TODO: assign check, if this can fail after passing the previous + // barriers, e.g. due to corrupted files. + return -3336; // "Not a Master Protocol transaction" + } + txobj->push_back(Pair("sendingaddress", tmpBuyer)); // get the details of sub records for payment(s) in the tx and push into an array Array purchases; @@ -1512,20 +1425,15 @@ static int populateRPCTransactionObject(uint256 txid, Object *txobj, string filt uint64_t vout; uint64_t nValue; p_txlistdb->getPurchaseDetails(wtxid,purchaseNumber,&buyer,&seller,&vout,&propertyId,&nValue); - bIsMine = false; - bIsMine = IsMyAddress(buyer); - if (!bIsMine) - { - bIsMine = IsMyAddress(seller); - } + bIsMine = IsMyAddress(buyer) || IsMyAddress(seller); if (!filterAddress.empty()) if ((buyer != filterAddress) && (seller != filterAddress)) return -1; // return negative rc if filtering & no match uint64_t amountPaid = wtx.vout[vout].nValue; purchaseObj.push_back(Pair("vout", vout)); - purchaseObj.push_back(Pair("amountpaid", FormatDivisibleMP(amountPaid))); + purchaseObj.push_back(Pair("amountpaid", FormatDivisibleAmount(amountPaid))); purchaseObj.push_back(Pair("ismine", bIsMine)); purchaseObj.push_back(Pair("referenceaddress", seller)); purchaseObj.push_back(Pair("propertyid", propertyId)); - purchaseObj.push_back(Pair("amountbought", FormatDivisibleMP(nValue))); + purchaseObj.push_back(Pair("amountbought", FormatDivisibleAmount(nValue))); purchaseObj.push_back(Pair("valid", true)); //only valid purchases are stored, anything else is regular BTC tx purchases.push_back(purchaseObj); } @@ -1679,11 +1587,7 @@ static int populateRPCTransactionObject(uint256 txid, Object *txobj, string filt { // test sender and reference against ismine to determine which address is ours // if both ours (eg sending to another address in wallet) use reference - bIsMine = IsMyAddress(senderAddress); - if (!bIsMine) - { - bIsMine = IsMyAddress(refAddress); - } + bIsMine = IsMyAddress(senderAddress) || IsMyAddress(refAddress); txobj->push_back(Pair("txid", wtxid.GetHex())); txobj->push_back(Pair("sendingaddress", senderAddress)); if (showReference) txobj->push_back(Pair("referenceaddress", refAddress)); @@ -1698,29 +1602,14 @@ static int populateRPCTransactionObject(uint256 txid, Object *txobj, string filt txobj->push_back(Pair("propertyname", propertyName)); } txobj->push_back(Pair("divisible", divisible)); - if (divisible) - { - txobj->push_back(Pair("amount", FormatDivisibleMP(amount))); //divisible, format w/ bitcoins VFA func - } - else - { - txobj->push_back(Pair("amount", FormatIndivisibleMP(amount))); //indivisible, push raw 64 - } + txobj->push_back(Pair("amount", FormatTokenAmount(amount, divisible))); if (crowdPurchase) { txobj->push_back(Pair("purchasedpropertyid", crowdPropertyId)); txobj->push_back(Pair("purchasedpropertyname", crowdName)); txobj->push_back(Pair("purchasedpropertydivisible", crowdDivisible)); - if (crowdDivisible) - { - txobj->push_back(Pair("purchasedtokens", FormatDivisibleMP(crowdTokens))); //divisible, format w/ bitcoins VFA func - txobj->push_back(Pair("issuertokens", FormatDivisibleMP(issuerTokens))); - } - else - { - txobj->push_back(Pair("purchasedtokens", FormatIndivisibleMP(crowdTokens))); //indivisible, push raw 64 - txobj->push_back(Pair("issuertokens", FormatIndivisibleMP(issuerTokens))); - } + txobj->push_back(Pair("purchasedtokens", FormatDivisibleAmount(crowdTokens, crowdDivisible))); + txobj->push_back(Pair("issuertokens", FormatDivisibleAmount(issuerTokens, crowdDivisible))); } if (MSC_TYPE_TRADE_OFFER == MPTxTypeInt) { @@ -1777,12 +1666,13 @@ Value gettransaction_MP(const Array& params, bool fHelp) { switch (populateResult) { - case -3331: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - case -3332: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Exception: blockHash is 0, is transaction unconfirmed?"); - case -3333: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Exception: pBlockIndex is NULL, is transaction unconfirmed?"); - case -3334: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Exception: Crowdsale Purchase but Property ID does not exist. This may be a bug."); - case -3335: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a Master Protocol transaction but TX exists in levelDB. This may be a bug."); + case -3331: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction."); // GetTransaction failed + case -3332: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unconfirmed transactions are not supported."); // blockHash is 0 + case -3333: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not part of the active chain."); // pBlockIndex is NULL + case -3334: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Potential database corruption: \"Crowdsale Purchase\" without valid Property ID."); + case -3335: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Potential database corruption: Invalid transaction found."); case -3336: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a Master Protocol transaction"); + case -3337: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a Master Protocol transaction"); // Faulty transaction slipped through } } // everything seems ok, return the object diff --git a/src/qt/sendmpdialog.cpp b/src/qt/sendmpdialog.cpp index 73650d7c70de..5e916c7f1191 100644 --- a/src/qt/sendmpdialog.cpp +++ b/src/qt/sendmpdialog.cpp @@ -58,6 +58,8 @@ using namespace leveldb; #include "mastercore_dex.h" #include "mastercore_tx.h" #include "mastercore_sp.h" +#include "mastercore_convert.h" +#include "mastercore_format.h" #include #include @@ -147,7 +149,7 @@ void SendMPDialog::updateFrom() } else { - string feeWarning = "Only " + FormatDivisibleMP(inputTotal) + " BTC are available at the sending address for fees, you can attempt to send the transaction anyway but this *may* not be sufficient."; + string feeWarning = "Only " + FormatDivisibleAmount(inputTotal) + " BTC are available at the sending address for fees, you can attempt to send the transaction anyway but this *may* not be sufficient."; ui->feeWarningLabel->setText(QString::fromStdString(feeWarning)); ui->feeWarningLabel->setVisible(true); } @@ -217,13 +219,13 @@ void SendMPDialog::updateBalances() if (propertyId>2) tokenLabel = " SPT"; if (isPropertyDivisible(propertyId)) { - balanceLabel = QString::fromStdString("Address Balance (Available): " + FormatDivisibleMP(balanceAvailable) + tokenLabel); - globalLabel = QString::fromStdString("Wallet Balance (Available): " + FormatDivisibleMP(globalAvailable) + tokenLabel); + balanceLabel = QString::fromStdString("Address Balance (Available): " + FormatDivisibleAmount(balanceAvailable) + tokenLabel); + globalLabel = QString::fromStdString("Wallet Balance (Available): " + FormatDivisibleAmount(globalAvailable) + tokenLabel); } else { - balanceLabel = QString::fromStdString("Address Balance (Available): " + FormatIndivisibleMP(balanceAvailable) + tokenLabel); - globalLabel = QString::fromStdString("Wallet Balance (Available): " + FormatIndivisibleMP(globalAvailable) + tokenLabel); + balanceLabel = QString::fromStdString("Address Balance (Available): " + FormatIndivisibleAmount(balanceAvailable) + tokenLabel); + globalLabel = QString::fromStdString("Wallet Balance (Available): " + FormatIndivisibleAmount(globalAvailable) + tokenLabel); } ui->addressBalanceLabel->setText(balanceLabel); ui->globalBalanceLabel->setText(globalLabel); @@ -292,7 +294,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", @@ -327,7 +329,7 @@ void SendMPDialog::sendMPTransaction() string spNum = static_cast( &(ostringstream() << propertyId) )->str(); propDetails += " (#" + spNum + ")"; strMsgText += "From: " + fromAddress.ToString() + "\nTo: " + refAddress.ToString() + "\nProperty: " + propDetails + "\nAmount that will be sent: "; - if (divisible) { strMsgText += FormatDivisibleMP(sendAmount); } else { strMsgText += FormatIndivisibleMP(sendAmount); } + strMsgText += FormatTokenAmount(sendAmount, divisible); strMsgText += "\n\nAre you sure you wish to send this transaction?"; QString msgText = QString::fromStdString(strMsgText); QMessageBox::StandardButton responseClick; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 43be1fd9365d..9e4912f9b92f 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -61,6 +61,7 @@ using namespace leveldb; #include "mastercore_dex.h" #include "mastercore_tx.h" #include "mastercore_sp.h" +#include "mastercore_format.h" #include #include @@ -897,13 +898,13 @@ int MatrixModel::fillin(unsigned int propertyId) bool divisible = isPropertyDivisible(propertyId); if (divisible) { - ql_avl.append(QString::fromStdString(FormatDivisibleMP(available))); - ql_res.append(QString::fromStdString(FormatDivisibleMP(reserved))); + ql_avl.append(QString::fromStdString(FormatDivisibleAmount(available))); + ql_res.append(QString::fromStdString(FormatDivisibleAmount(reserved))); } else { - ql_avl.append(QString::fromStdString(FormatIndivisibleMP(available))); - ql_res.append(QString::fromStdString(FormatIndivisibleMP(reserved))); + ql_avl.append(QString::fromStdString(FormatIndivisibleAmount(available))); + ql_res.append(QString::fromStdString(FormatIndivisibleAmount(reserved))); } ++count; } @@ -922,13 +923,13 @@ int MatrixModel::fillin(unsigned int propertyId) bool divisible = isPropertyDivisible(propertyId+2147483647); if (divisible) { - ql_avl.append(QString::fromStdString(FormatDivisibleMP(available))); - ql_res.append(QString::fromStdString(FormatDivisibleMP(reserved))); + ql_avl.append(QString::fromStdString(FormatDivisibleAmount(available))); + ql_res.append(QString::fromStdString(FormatDivisibleAmount(reserved))); } else { - ql_avl.append(QString::fromStdString(FormatIndivisibleMP(available))); - ql_res.append(QString::fromStdString(FormatIndivisibleMP(reserved))); + ql_avl.append(QString::fromStdString(FormatIndivisibleAmount(available))); + ql_res.append(QString::fromStdString(FormatIndivisibleAmount(reserved))); } ++count; } @@ -960,13 +961,13 @@ int MatrixModel::fillin(unsigned int propertyId) ql_addr.append((my_it->first).c_str()); if (divisible) { - ql_avl.append(QString::fromStdString(FormatDivisibleMP(available))); - ql_res.append(QString::fromStdString(FormatDivisibleMP(reserved))); + ql_avl.append(QString::fromStdString(FormatDivisibleAmount(available))); + ql_res.append(QString::fromStdString(FormatDivisibleAmount(reserved))); } else { - ql_avl.append(QString::fromStdString(FormatIndivisibleMP(available))); - ql_res.append(QString::fromStdString(FormatIndivisibleMP(reserved))); + ql_avl.append(QString::fromStdString(FormatIndivisibleAmount(available))); + ql_res.append(QString::fromStdString(FormatIndivisibleAmount(reserved))); } ++count; } diff --git a/src/test/Makefile.am b/src/test/Makefile.am index e12f4904f14c..ae952e4d0558 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -47,6 +47,9 @@ test_bitcoin_SOURCES = \ getarg_tests.cpp \ key_tests.cpp \ main_tests.cpp \ + mastercore_format_tests.cpp \ + mastercore_roundtouint64_tests.cpp \ + mastercore_strtoint64_tests.cpp \ miner_tests.cpp \ mruset_tests.cpp \ multisig_tests.cpp \ diff --git a/src/test/mastercore_format_tests.cpp b/src/test/mastercore_format_tests.cpp new file mode 100644 index 000000000000..078db78a8d49 --- /dev/null +++ b/src/test/mastercore_format_tests.cpp @@ -0,0 +1,186 @@ +#include "mastercore_format.h" + +#include + +#include + +BOOST_AUTO_TEST_SUITE(mastercore_format_tests) + +BOOST_AUTO_TEST_CASE(mastercore_format_indivisible) +{ + // positive numbers + BOOST_CHECK("0" == FormatIndivisibleAmount(0)); + BOOST_CHECK("1" == FormatIndivisibleAmount(1)); + BOOST_CHECK("10" == FormatIndivisibleAmount(10)); + BOOST_CHECK("100" == FormatIndivisibleAmount(100)); + BOOST_CHECK("1000" == FormatIndivisibleAmount(1000)); + BOOST_CHECK("10000" == FormatIndivisibleAmount(10000)); + BOOST_CHECK("100000" == FormatIndivisibleAmount(100000)); + BOOST_CHECK("1000000" == FormatIndivisibleAmount(1000000)); + BOOST_CHECK("10000000" == FormatIndivisibleAmount(10000000)); + BOOST_CHECK("100000000" == FormatIndivisibleAmount(100000000)); + BOOST_CHECK("1000000000" == FormatIndivisibleAmount(1000000000)); + BOOST_CHECK("10000000000" == FormatIndivisibleAmount(10000000000)); + BOOST_CHECK("100000000000" == FormatIndivisibleAmount(100000000000)); + BOOST_CHECK("1000000000000" == FormatIndivisibleAmount(1000000000000)); + BOOST_CHECK("10000000000000" == FormatIndivisibleAmount(10000000000000)); + BOOST_CHECK("100000000000000" == FormatIndivisibleAmount(100000000000000)); + BOOST_CHECK("1000000000000000" == FormatIndivisibleAmount(1000000000000000)); + BOOST_CHECK("10000000000000000" == FormatIndivisibleAmount(10000000000000000)); + BOOST_CHECK("100000000000000000" == FormatIndivisibleAmount(100000000000000000)); + BOOST_CHECK("1000000000000000000" == FormatIndivisibleAmount(1000000000000000000)); + + // negative numbers + BOOST_CHECK("-1" == FormatIndivisibleAmount(-1)); + BOOST_CHECK("-10" == FormatIndivisibleAmount(-10)); + BOOST_CHECK("-100" == FormatIndivisibleAmount(-100)); + BOOST_CHECK("-1000" == FormatIndivisibleAmount(-1000)); + BOOST_CHECK("-10000" == FormatIndivisibleAmount(-10000)); + BOOST_CHECK("-100000" == FormatIndivisibleAmount(-100000)); + BOOST_CHECK("-1000000" == FormatIndivisibleAmount(-1000000)); + BOOST_CHECK("-10000000" == FormatIndivisibleAmount(-10000000)); + BOOST_CHECK("-100000000" == FormatIndivisibleAmount(-100000000)); + BOOST_CHECK("-1000000000" == FormatIndivisibleAmount(-1000000000)); + BOOST_CHECK("-10000000000" == FormatIndivisibleAmount(-10000000000)); + BOOST_CHECK("-100000000000" == FormatIndivisibleAmount(-100000000000)); + BOOST_CHECK("-1000000000000" == FormatIndivisibleAmount(-1000000000000)); + BOOST_CHECK("-10000000000000" == FormatIndivisibleAmount(-10000000000000)); + BOOST_CHECK("-100000000000000" == FormatIndivisibleAmount(-100000000000000)); + BOOST_CHECK("-1000000000000000" == FormatIndivisibleAmount(-1000000000000000)); + BOOST_CHECK("-10000000000000000" == FormatIndivisibleAmount(-10000000000000000)); + BOOST_CHECK("-100000000000000000" == FormatIndivisibleAmount(-100000000000000000)); + BOOST_CHECK("-1000000000000000000" == FormatIndivisibleAmount(-1000000000000000000)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_divisible_signed) +{ + // positive numbers + BOOST_CHECK("+0.00000000" == FormatDivisibleAmount(0, true)); + BOOST_CHECK("+0.00000001" == FormatDivisibleAmount(1, true)); + BOOST_CHECK("+0.00000010" == FormatDivisibleAmount(10, true)); + BOOST_CHECK("+0.00000100" == FormatDivisibleAmount(100, true)); + BOOST_CHECK("+0.00001000" == FormatDivisibleAmount(1000, true)); + BOOST_CHECK("+0.00010000" == FormatDivisibleAmount(10000, true)); + BOOST_CHECK("+0.00100000" == FormatDivisibleAmount(100000, true)); + BOOST_CHECK("+0.01000000" == FormatDivisibleAmount(1000000, true)); + BOOST_CHECK("+0.10000000" == FormatDivisibleAmount(10000000, true)); + BOOST_CHECK("+1.00000000" == FormatDivisibleAmount(100000000, true)); + BOOST_CHECK("+10.00000000" == FormatDivisibleAmount(1000000000, true)); + BOOST_CHECK("+100.00000000" == FormatDivisibleAmount(10000000000, true)); + BOOST_CHECK("+1000.00000000" == FormatDivisibleAmount(100000000000, true)); + BOOST_CHECK("+10000.00000000" == FormatDivisibleAmount(1000000000000, true)); + BOOST_CHECK("+100000.00000000" == FormatDivisibleAmount(10000000000000, true)); + BOOST_CHECK("+1000000.00000000" == FormatDivisibleAmount(100000000000000, true)); + BOOST_CHECK("+10000000.00000000" == FormatDivisibleAmount(1000000000000000, true)); + BOOST_CHECK("+100000000.00000000" == FormatDivisibleAmount(10000000000000000, true)); + BOOST_CHECK("+1000000000.00000000" == FormatDivisibleAmount(100000000000000000, true)); + BOOST_CHECK("+10000000000.00000000" == FormatDivisibleAmount(1000000000000000000, true)); + + // negative numbers + BOOST_CHECK("-0.00000001" == FormatDivisibleAmount(-1, true)); + BOOST_CHECK("-0.00000010" == FormatDivisibleAmount(-10, true)); + BOOST_CHECK("-0.00000100" == FormatDivisibleAmount(-100, true)); + BOOST_CHECK("-0.00001000" == FormatDivisibleAmount(-1000, true)); + BOOST_CHECK("-0.00010000" == FormatDivisibleAmount(-10000, true)); + BOOST_CHECK("-0.00100000" == FormatDivisibleAmount(-100000, true)); + BOOST_CHECK("-0.01000000" == FormatDivisibleAmount(-1000000, true)); + BOOST_CHECK("-0.10000000" == FormatDivisibleAmount(-10000000, true)); + BOOST_CHECK("-1.00000000" == FormatDivisibleAmount(-100000000, true)); + BOOST_CHECK("-10.00000000" == FormatDivisibleAmount(-1000000000, true)); + BOOST_CHECK("-100.00000000" == FormatDivisibleAmount(-10000000000, true)); + BOOST_CHECK("-1000.00000000" == FormatDivisibleAmount(-100000000000, true)); + BOOST_CHECK("-10000.00000000" == FormatDivisibleAmount(-1000000000000, true)); + BOOST_CHECK("-100000.00000000" == FormatDivisibleAmount(-10000000000000, true)); + BOOST_CHECK("-1000000.00000000" == FormatDivisibleAmount(-100000000000000, true)); + BOOST_CHECK("-10000000.00000000" == FormatDivisibleAmount(-1000000000000000, true)); + BOOST_CHECK("-100000000.00000000" == FormatDivisibleAmount(-10000000000000000, true)); + BOOST_CHECK("-1000000000.00000000" == FormatDivisibleAmount(-100000000000000000, true)); + BOOST_CHECK("-10000000000.00000000" == FormatDivisibleAmount(-1000000000000000000, true)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_divisible_unsigned) +{ + // positive numbers + BOOST_CHECK("0.00000000" == FormatDivisibleAmount(0, false)); + BOOST_CHECK("0.00000001" == FormatDivisibleAmount(1, false)); + BOOST_CHECK("0.00000010" == FormatDivisibleAmount(10, false)); + BOOST_CHECK("0.00000100" == FormatDivisibleAmount(100, false)); + BOOST_CHECK("0.00001000" == FormatDivisibleAmount(1000, false)); + BOOST_CHECK("0.00010000" == FormatDivisibleAmount(10000, false)); + BOOST_CHECK("0.00100000" == FormatDivisibleAmount(100000, false)); + BOOST_CHECK("0.01000000" == FormatDivisibleAmount(1000000, false)); + BOOST_CHECK("0.10000000" == FormatDivisibleAmount(10000000, false)); + BOOST_CHECK("1.00000000" == FormatDivisibleAmount(100000000, false)); + BOOST_CHECK("10.00000000" == FormatDivisibleAmount(1000000000, false)); + BOOST_CHECK("100.00000000" == FormatDivisibleAmount(10000000000, false)); + BOOST_CHECK("1000.00000000" == FormatDivisibleAmount(100000000000, false)); + BOOST_CHECK("10000.00000000" == FormatDivisibleAmount(1000000000000, false)); + BOOST_CHECK("100000.00000000" == FormatDivisibleAmount(10000000000000, false)); + BOOST_CHECK("1000000.00000000" == FormatDivisibleAmount(100000000000000, false)); + BOOST_CHECK("10000000.00000000" == FormatDivisibleAmount(1000000000000000, false)); + BOOST_CHECK("100000000.00000000" == FormatDivisibleAmount(10000000000000000, false)); + BOOST_CHECK("1000000000.00000000" == FormatDivisibleAmount(100000000000000000, false)); + BOOST_CHECK("10000000000.00000000" == FormatDivisibleAmount(1000000000000000000, false)); + + // negative numbers + BOOST_CHECK("0.00000001" == FormatDivisibleAmount(-1, false)); + BOOST_CHECK("0.00000010" == FormatDivisibleAmount(-10, false)); + BOOST_CHECK("0.00000100" == FormatDivisibleAmount(-100, false)); + BOOST_CHECK("0.00001000" == FormatDivisibleAmount(-1000, false)); + BOOST_CHECK("0.00010000" == FormatDivisibleAmount(-10000, false)); + BOOST_CHECK("0.00100000" == FormatDivisibleAmount(-100000, false)); + BOOST_CHECK("0.01000000" == FormatDivisibleAmount(-1000000, false)); + BOOST_CHECK("0.10000000" == FormatDivisibleAmount(-10000000, false)); + BOOST_CHECK("1.00000000" == FormatDivisibleAmount(-100000000, false)); + BOOST_CHECK("10.00000000" == FormatDivisibleAmount(-1000000000, false)); + BOOST_CHECK("100.00000000" == FormatDivisibleAmount(-10000000000, false)); + BOOST_CHECK("1000.00000000" == FormatDivisibleAmount(-100000000000, false)); + BOOST_CHECK("10000.00000000" == FormatDivisibleAmount(-1000000000000, false)); + BOOST_CHECK("100000.00000000" == FormatDivisibleAmount(-10000000000000, false)); + BOOST_CHECK("1000000.00000000" == FormatDivisibleAmount(-100000000000000, false)); + BOOST_CHECK("10000000.00000000" == FormatDivisibleAmount(-1000000000000000, false)); + BOOST_CHECK("100000000.00000000" == FormatDivisibleAmount(-10000000000000000, false)); + BOOST_CHECK("1000000000.00000000" == FormatDivisibleAmount(-100000000000000000, false)); + BOOST_CHECK("10000000000.00000000" == FormatDivisibleAmount(-1000000000000000000, false)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_indivisible_limits) +{ + BOOST_CHECK("9223372036854775807" == FormatIndivisibleAmount(9223372036854775807)); + BOOST_CHECK("-9223372036854775807" == FormatIndivisibleAmount(-9223372036854775807)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_divisible_unsigned_limits) +{ + BOOST_CHECK("92233720368.54775807" == FormatDivisibleAmount(9223372036854775807)); + BOOST_CHECK("-92233720368.54775807" == FormatDivisibleAmount(-9223372036854775807)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_divisible_signed_limits) +{ + BOOST_CHECK("+92233720368.54775807" == FormatDivisibleAmount(9223372036854775807, true)); + BOOST_CHECK("-92233720368.54775807" == FormatDivisibleAmount(-9223372036854775807, true)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_token_amount_divisible) +{ + BOOST_CHECK("9223372036854775807" == FormatTokenAmount(9223372036854775807, false)); + BOOST_CHECK("-9223372036854775807" == FormatTokenAmount(-9223372036854775807, false)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_token_amount_indivisible) +{ + BOOST_CHECK("92233720368.54775807" == FormatTokenAmount(9223372036854775807, true)); + BOOST_CHECK("-92233720368.54775807" == FormatTokenAmount(-9223372036854775807, true)); +} + +BOOST_AUTO_TEST_CASE(mastercore_format_amounts_auto_sign) +{ + BOOST_CHECK("1" == FormatTokenAmount(1)); + BOOST_CHECK("-1" == FormatTokenAmount(-1)); + + BOOST_CHECK("0.00000001" == FormatDivisibleAmount(1)); + BOOST_CHECK("-0.00000001" == FormatDivisibleAmount(-1)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mastercore_roundtouint64_tests.cpp b/src/test/mastercore_roundtouint64_tests.cpp new file mode 100644 index 000000000000..14e8d8746c18 --- /dev/null +++ b/src/test/mastercore_roundtouint64_tests.cpp @@ -0,0 +1,36 @@ +#include "mastercore_convert.h" + +#include +#include + +#include + +BOOST_AUTO_TEST_SUITE(mastercore_roundtouint64_tests) + +BOOST_AUTO_TEST_CASE(mastercore_roundtouint64_abs) +{ + uint64_t ul = 1UL; + long double ld = 1.0L; + + while (ul < UINT64_MAX && ld < UINT64_MAX) { + BOOST_CHECK(ul == RoundToUInt64(ld)); + ul = ul * 2UL; + ld = ld * 2.0L; + } +} + +BOOST_AUTO_TEST_CASE(mastercore_roundtouint64_limits) +{ + BOOST_CHECK(9223372036854775807UL == RoundToUInt64(-9223372036854775807.5L)); + BOOST_CHECK(9223372036854775807UL == RoundToUInt64(9223372036854775807.0L)); + BOOST_CHECK(0UL == RoundToUInt64(0.0L)); + BOOST_CHECK(1UL == RoundToUInt64(1.49999999L)); + BOOST_CHECK(2UL == RoundToUInt64(1.50000000L)); + BOOST_CHECK(0UL == RoundToUInt64(-0.0L)); + BOOST_CHECK(0UL == RoundToUInt64(-1.49999999L)); + BOOST_CHECK(1UL == RoundToUInt64(-1.50000000L)); + + // TODO: more testing. Is even -1.499 -> 0 the desired outcome? +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mastercore_strtoint64_tests.cpp b/src/test/mastercore_strtoint64_tests.cpp new file mode 100644 index 000000000000..8811ce08d349 --- /dev/null +++ b/src/test/mastercore_strtoint64_tests.cpp @@ -0,0 +1,54 @@ +#include "mastercore_convert.h" + +#include + +#include + +BOOST_AUTO_TEST_SUITE(mastercore_strtoint64_tests) + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_invidisible_positive) +{ + BOOST_CHECK(9223372036854775807 == StrToInt64("9223372036854775807", false)); // max int64 + BOOST_CHECK(4000000000000000 == StrToInt64("4000000000000000", false)); // big num + BOOST_CHECK(0 == StrToInt64("0", false)); // zero amount +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_invidisible_negative) +{ + BOOST_CHECK(0 == StrToInt64("9223372036854775808", false)); // over max int64 + BOOST_CHECK(0 == StrToInt64("-4", false)); // negative +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_divisible_positive) +{ + BOOST_CHECK(0 == StrToInt64("0.000", true)); + BOOST_CHECK(9223372036854775807 == StrToInt64("92233720368.54775807", true)); // max int64 + BOOST_CHECK(9223372036854775807 == StrToInt64("92233720368.547758070", true)); // 8 digits + BOOST_CHECK(4 == StrToInt64("0.00000004", true)); // check padding + BOOST_CHECK(40 == StrToInt64("0.0000004", true)); // check padding + BOOST_CHECK(40000 == StrToInt64("0.0004", true)); // check padding + BOOST_CHECK(40000000 == StrToInt64("0.4", true)); // check padding + BOOST_CHECK(400000000 == StrToInt64("4.0", true)); // check padding + BOOST_CHECK(4000000000 == StrToInt64("40.00000000000099", true)); // over 8 digits +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_divisible_negative) +{ + BOOST_CHECK(0 == StrToInt64("92233720368.54775808", true)); // over max int64 + BOOST_CHECK(0 == StrToInt64("1234..12345678", true)); // more than one decimal in string + BOOST_CHECK(0 == StrToInt64("1234.12345A", true)); // alpha chars in string + BOOST_CHECK(0 == StrToInt64("-4.0", true)); // negative +} + +BOOST_AUTO_TEST_CASE(mastercore_strtoint64_other_chars) +{ + BOOST_CHECK(0 == StrToInt64("8.765432101.2345687890", true)); + BOOST_CHECK(876543210 == StrToInt64("8.7654321012345687890", true)); + + BOOST_CHECK(8 == StrToInt64("8.76543210123456878901", false)); + BOOST_CHECK(8 == StrToInt64("8.765432101.2345687890", false)); + BOOST_CHECK(2345 == StrToInt64("2345.AbCdEhf71z1.23", false)); + BOOST_CHECK(0 == StrToInt64("2345.AbCdEFG71z88-1.23", false)); +} + +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()); } - -} - -